2012-03-27 19 views
7

में एक समारोह के एकाधिक परिभाषा यह C/C++ समारोह परिभाषा पर सवाल है। चर्चा की गई कोड स्थिर लाइब्रेरी libRmathR में Rmath.h शीर्षलेख फ़ाइल में परिभाषाएं प्रदान करती है।C/C++ कोड

लाइब्रेरी के लिए documentation प्रदान किया गया है कि यह उपयोगकर्ता के लिए double unif_rand(void) फ़ंक्शन परिभाषा प्रदान करने के लिए वैकल्पिक है।

तो मेरे सवाल है, तो इस तरह के एक समारोह परिभाषा वैकल्पिक है है, एक से अधिक समारोह परिभाषाओं की एक समस्या जो C/C++ में अनुमति नहीं है नहीं होगी?

संपादित करें: यह कैसे चीजें स्रोत कोड देख बिना काम करता है पर सट्टा करने के लिए आकर्षक हो सकता है, लेकिन यह नहीं है कि मैं क्या चाहता हूँ। मुझे यह जानने में दिलचस्पी है कि यह वास्तव में काम करता है, इसलिए आपको शायद इस प्रश्न का उत्तर देने के लिए source code औरपढ़ने की आवश्यकता होगी।

+0

मेरा अनुमान होगा कि समारोह डीईएफ़ ताकि यदि आप इसे परिभाषित करते हैं, तो तुम्हारा लिंकर से पहले पाया जाता है, तो एक पहले से ही वहाँ नजरअंदाज कर दिया जाएगा एक #ifdef में है। – baash05

उत्तर

15

जब आप आवेदन से जुड़ा हुआ है, अनसुलझे प्रतीक पुस्तकालयों उपलब्ध कराने का उपयोग कर का समाधान हो जाएगा। आप एक समारोह को परिभाषित नहीं है, तो यह लिंकिंग, इसलिए, जुड़ा हुआ है, कि प्रतीक librmath का उपयोग कर हल करने इस मामले में की कोशिश करेंगे के दौरान एक अनसुलझे प्रतीक होगा। यदि एक या अधिक प्रतीकों का समाधान नहीं किया जा सकता है, तो आपको एक लिंकर त्रुटि मिल जाएगी।

हालांकि, यदि आप अपने कोड में फ़ंक्शन को परिभाषित करते हैं, तो इसे पहले से ही लिंक करने के दौरान परिभाषित किया जाएगा, इसलिए बाहरी पुस्तकालयों के प्रतीकों का उपयोग करके इसे हल करने की आवश्यकता नहीं होगी।

आप ऐसा नहीं कर सकते क्या अपने आवेदन में एक बार से एक ही प्रतीक अधिक परिभाषित करने के लिए है।

संपादित करें: चूंकि किसी अन्य उत्तर में बहुत बहस है, इसलिए मैंने एक व्यावहारिक उदाहरण बना दिया है। मैं एक साझा वस्तु (विंडोज़ में DLL- के समान) है, जो परिभाषित करता है और एक समारोह foo निर्यात बना लिया है:

//lib.h 
extern "C" { 
    void foo(); 
    void bar(); 
}; 

//lib.cpp 
#include <iostream> 
#include "lib.h" 

void foo() { 
    std::cout << "From lib\n"; 
} 

void bar() { 
    std::cout << "Bar, calling foo\n"; 
    foo(); 
} 

आदेश में इस साझा वस्तु का परीक्षण करने के लिए, मैं एक आवेदन जो इसके साथ जुड़ा हुआ है बना लिया है :

//test.cpp 
#include <iostream> 
#include "lib.h" 

void foo() { 
    std::cout << "From app\n"; 
} 

int main() { 
    bar(); 
} 

मैं दोनों में संकलित किया है, साझा वस्तु और आवेदन:

g++ lib.cpp -o libtest.so -Wall -fPIC -shared -Wl,--export-dynamic -Wl,-soname,libtest.so -Wl,-z,defs 
g++ test.cpp -o test -L. -ltest 

और जब मैं test निष्पादित, 01,239,140 करने के लिए पुस्तकालय की स्थापना पथ

[email protected]:/tmp$ LD_LIBRARY_PATH="." ./test 
Bar, calling foo 
From app 

आप देख सकते हैं, foo समारोह आवेदन (नहीं साझा वस्तु) में परिभाषित कहा जाता है:, इसलिए मेरे साझा वस्तु लोड किया जा सकता, मैं इस उत्पादन मिलता है। आप मूल रूप से किसी साझा ऑब्जेक्ट में प्रत्येक निर्यात किए गए प्रतीक के लिए ऐसा कर सकते हैं।

EDIT2: मैंने lib.h में एक और निर्यात किया गया फ़ंक्शन जोड़ा है। एप्लिकेशन अब इस फ़ंक्शन को कॉल करता है, जो कॉलिंग को समाप्त करता है। परिणाम अपेक्षित के समान है।

EDIT3: ठीक है, चलो गहरे जाओ।

Dump of assembler code for function [email protected]: 
    0x0804855c <+0>: jmp DWORD PTR ds:0x804a004 
    0x08048562 <+6>: push 0x8 
    0x08048567 <+11>: jmp 0x804853c 

हम 0x804a004 संबोधित करने के लिए जाते हैं:

Dump of assembler code for function _GLOBAL_OFFSET_TABLE_: 
    0x08049ff4 <+0>: or  BYTE PTR [edi+0x804],bl 
    0x08049ffa <+6>: add BYTE PTR [eax],al 
    0x08049ffc <+8>: add BYTE PTR [eax],al 
    0x08049ffe <+10>: add BYTE PTR [eax],al 
    ..... 

आप देख सकते हैं, यह वैश्विक ऑफसेट टेबल पर कूद रहा है इस समारोह bar से डंप है। आप GOT here और here के बारे में पढ़ सकते हैं। डायनामिक प्रतीकों (जिन्हें रनटाइम पर हल किया जाता है) इस तालिका में संग्रहीत होते हैं। जब भी आप एक प्रतीक को कॉल करते हैं जिसे रनटाइम पर हल किया जाना चाहिए, तो आप वास्तव में इस तालिका में कूदते हैं, और उसके बाद इस तालिका की संबंधित प्रविष्टि में संग्रहीत पते पर जाएं। चूंकि एप्लिकेशन foo को परिभाषित करता है, इसलिए GOT में test.cpp से परिभाषा का पता होता है, न कि हमारे साझा ऑब्जेक्ट में से एक।

EDIT4: ठीक है, अंतिम संपादन। दस्तावेज़ से हवाला देते हुए:

आप वर्दी यादृच्छिक संख्या जनरेटर

double unif_rand(void) 

की आपूर्ति या (आपूर्ति की एक का उपयोग करें और एक गतिशील पुस्तकालय या DLL के साथ आपूर्ति की एक का उपयोग करना होगा करने की आवश्यकता होगी (...)

प्रलेखन स्पष्ट रूप से कहते हैं कि आप आप unif_rand के कार्यान्वयन के मालिक हैं आप गतिशील पुस्तकालय उपयोग कर रहे हैं प्रदान नहीं कर सकते हैं। इसलिए, मुझे विश्वास है कि मैं क्या ने कहा, वास्तव में ans आपका प्रश्न पूछता है

+0

यह अनिवार्य रूप से वही बात कह रहा है जैसा मैंने कहा था। – Nawaz

+0

अंतिम अनुच्छेद अनिवार्य रूप से वही है। बाकी नहीं है। – mfontanini

+0

वास्तव में कैसे? बाकी सिर्फ विवरण है। – Nawaz

0

एक स्थिर पुस्तकालय लिंक करने स्थिर पुस्तकालय के अंदर सभी वस्तुओं को जोड़ने से थोड़ा अलग है। स्थिर पुस्तकालय में

परिभाषाएँ केवल अगर जरूरत में खींच रहे हैं, तो वे एक से अधिक परिभाषा त्रुटि नहीं हो सकता है।

यह thewell-known एक स्थिर पुस्तकालय के अंदर वैश्विक initializers के problem नहीं चल उदाहरण के लिए, कुछ साइड इफेक्ट जब मुख्य कार्यक्रम संदर्भ वस्तु में कुछ भी नहीं।

+0

एक छोटी टिप्पणी; यह स्पष्ट करने के लायक हो सकता है "उदाहरण के लिए एक स्थिर लाइब्रेरी के अंदर वैश्विक प्रारंभकर्ताओं की प्रसिद्ध समस्या तब नहीं चल रही जब मुख्य प्रोग्राम संदर्भ में कुछ भी नहीं है" क्योंकि यह किसी समस्या की तरह नहीं लगता है लेकिन सही लगता है; "ऑब्जेक्ट का उपयोग नहीं किया जाता है, इसलिए प्रारंभिकरण का कोई ओवरहेड" ऑब्जेक्ट का उपयोग नहीं होने के बावजूद बेहतर लगता है, फिर भी प्रारंभिकता का ओवरहेड है "। क्या पहले से ही एक स्टैक ओवरफ्लो प्रश्न है जिसे संदर्भ के रूप में उपयोग किया जा सकता है? सिर्फ एक विचार। – gbulmer

+0

क्या आप कुछ सी ++ कोड और संकलन आदेशों के साथ विस्तृत कर सकते हैं? – ggg

+0

@ जुबल्मर: http://stackoverflow.com/questions/6317796/ctor-init-not-calling-the-global-ctor-instances-in-library और http://stackoverflow.com/questions/9459980/c- ग्लोबल-वेरिएबल-न-प्रारंभिक-कब-लिंक्ड-थ्रू-स्टेटिक-लाइब्रेरी-लेकिन-ओके और http://stackoverflow.com/questions/6221947/ensuring-that-a-static-method-gets-called- पहले- मुख्य –