නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂයක් යනු කුමක්ද සහ එය නිවැරදි කරන්නේ කෙසේද?


1512

නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂ මොනවාද? පොදු හේතු මොනවාද සහ ඒවා නිවැරදි කරන්නේ / වළක්වා ගන්නේ කෙසේද?

ඔබේම සංස්කරණය කිරීමට / එකතු කිරීමට නිදහස් වන්න.


Uch ලූචියන් ග්‍රිගෝර්ට 'පිළිතුරක් එක් කිරීමට නිදහස්ව සිටින්න ' ඔබ අවසර දීමට කැමති නම්, ඔබේ මූලික පිළිතුර වන අදාළ සබැඳිය (IMHO) එක් කිරීමට මම කැමැත්තෙමි.
ῥεῖα ῥεῖ

21
මෙම ප්‍රශ්නය ප්‍රයෝජනවත් පිළිතුරක් පිළිගැනීමට වඩා සාමාන්‍ය ය. මේ පිළිබඳව අදහස් දක්වන 1000+ කීර්තිනාම සංඛ්‍යාව මට විශ්වාස කළ නොහැක. මේ අතර, සංවේදී හා සංවෘත බොහෝ ප්‍රශ්න මට පෙනේ.
ඇල්බට් වැන් ඩර් හෝස්ට්

10
L ඇල්බර්ට්වන්ඩර්හෝස්ට් "මෙම ප්‍රශ්නය ප්‍රයෝජනවත් පිළිතුරක් පිළිගැනීමට වඩා සාමාන්‍ය ය" පහත පිළිතුරු ප්‍රයෝජනවත් නොවේ ද?
එල්එෆ්

4
සාමාන්‍ය ලෙස සලකුණු කර ඇති ප්‍රශ්නවලට බොහෝ පිළිතුරු මෙන්ම ඒවා ප්‍රයෝජනවත් විය හැකිය.
ඇල්බට් වැන් ඩර් හෝස්ට්

1
අවම වශයෙන් ප්‍රජනනය කළ හැකි උදාහරණයක් අපි බොහෝ නව පරිශීලකයින්ගෙන් අවංකව ඉල්ලා සිටින දෙයක් ලෙස දැකීමට කැමැත්තෙමි. මම එයින් කිසිවක් අදහස් නොකරමි, එය සාධාරණයි - අප විසින්ම අප වෙත දැනුම් නොදෙන නීති රීති මිනිසුන් විසින් අනුගමනය කරනු ඇතැයි අපේක්ෂා කළ නොහැක.
ඩැනිලෝ

Answers:


855

2.2 හි නිශ්චිතව දක්වා ඇති පරිදි C ++ වැඩසටහනක් සම්පාදනය කිරීම පියවර කිහිපයකින් සිදු වේ (යොමු කිරීම සඳහා කීත් තොම්සන්ට බැර) :

පරිවර්තන සින්ටැක්ස් රීති අතර ප්‍රමුඛතාවය පහත දැක්වෙන අදියරයන් මගින් නියම කරනු ලැබේ [පාදසටහන බලන්න] .

  1. අවශ්‍ය නම් භෞතික ප්‍රභව ගොනු අක්‍ෂර ක්‍රියාත්මක කිරීම-නිර්වචනය කර ඇති පරිදි මූලික මූලාශ්‍ර අක්ෂර කට්ටලයට (අවශ්‍ය රේඛා දර්ශකයන් සඳහා නව රේඛා අක්ෂර හඳුන්වා දීම) සිතියම් ගත කරනු ලැබේ. [SNIP]
  2. බැක්ස්ලෑෂ් අක්ෂරයක (\) සෑම අවස්ථාවකම වහාම නව රේඛා අක්‍ෂරයක් මකා දමනු ලැබේ. [SNIP]
  3. ප්‍රභව ගොනුව පෙර සැකසුම් ටෝකන (2.5) සහ සුදු-අවකාශ අක්ෂර අනුපිළිවෙලට (අදහස් ඇතුළුව) දිරාපත් වේ. [SNIP]
  4. පෙර සැකසුම් විධානයන් ක්‍රියාත්මක කරනු ලැබේ, සාර්ව ආයාචනා පුළුල් වේ, සහ _ප්‍රාග්මා ඒකීය ක්‍රියාකරු ප්‍රකාශන ක්‍රියාත්මක වේ. [SNIP]
  5. සෑම ප්‍රභව අක්ෂර කට්ටලයකම වචනානුසාරයෙන් හෝ වචනාර්ථයෙන් වචනාර්ථයෙන්, මෙන්ම එක් එක් ගැලවීමේ අනුක්‍රමය සහ විශ්වීය-චරිත-නාමයක් අක්‍ෂර වචනාර්ථයෙන් හෝ අමු නොවන වචන වචනාර්ථයෙන් ක්‍රියාත්මක වන අක්‍ෂර කට්ටලයේ අනුරූප සාමාජිකයා බවට පරිවර්තනය වේ; [SNIP]
  6. යාබද නූල් වචනාර්ථ ටෝකන සංයුක්ත වේ.
  7. ටෝකන වෙන් කරන සුදු-අවකාශ අක්ෂර තවදුරටත් වැදගත් නොවේ. සෑම පෙර සැකසුම් ටෝකනයක්ම ටෝකනයක් බවට පරිවර්තනය වේ. (2.7). එහි ප්‍රති ing ලයක් ලෙස ටෝකන කෘතිමව හා අර්ථාන්විතව විශ්ලේෂණය කර පරිවර්තන ඒකකයක් ලෙස පරිවර්තනය කරනු ලැබේ. [SNIP]
  8. පරිවර්තන පරිවර්තන ඒකක සහ ක්ෂණික ඒකක පහත පරිදි සංයුක්ත වේ: [SNIP]
  9. සියලුම බාහිර ආයතන යොමු කිරීම් විසඳනු ලැබේ. වර්තමාන පරිවර්තනයේ අර්ථ දක්වා නැති ආයතන සඳහා බාහිර යොමු කිරීම් තෘප්තිමත් කිරීම සඳහා පුස්තකාල සංරචක සම්බන්ධ කර ඇත. එවැනි සියලු පරිවර්තක ප්‍රතිදානය වැඩසටහන් ක්‍රියාත්මක කිරීම සඳහා එහි ක්‍රියාකාරී පරිසරය තුළ ක්‍රියාත්මක කිරීමට අවශ්‍ය තොරතුරු අඩංගු වේ. (අවධාරණය මගේ)

[පාදසටහන] ප්‍රායෝගිකව විවිධ අවධීන් එකට නැමිය හැකි වුවද, ක්‍රියාත්මක කිරීම් මෙම වෙනම අදියරයන් මෙන් හැසිරිය යුතුය.

නිශ්චිත දෝෂයන් සම්පාදනය කිරීමේ මෙම අවසාන අදියරේදී සිදු වේ. මූලික වශයෙන් අදහස් කරන්නේ ඔබ ක්‍රියාත්මක කිරීමේ ලිපිගොනු සමූහයක් වස්තු ලිපිගොනු හෝ පුස්තකාලවලට සම්පාදනය කර ඇති අතර දැන් ඔබට ඒවා එකට වැඩ කිරීමට අවශ්‍ය බවයි.

ඔබ සංකේතය අර්ථ කියන්න aතුළ a.cpp. දැන්, එම සංකේතය b.cpp ප්රකාශ කර එය භාවිතා කර ඇත. සම්බන්ධ වීමට පෙර, එය සරලව උපකල්පනය කරන්නේ එම සංකේතය කොතැනක හෝ අර්ථ දක්වා ඇති බවයි , නමුත් එය තවමත් කොතැනදැයි ගණන් ගන්නේ නැත. සම්බන්ධක අවධිය සංකේතය සොයා ගැනීම සහ එය නිවැරදිව සම්බන්ධ කිරීම සඳහා වගකීම දරයි b.cpp(හොඳයි, ඇත්ත වශයෙන්ම එය භාවිතා කරන වස්තුවට හෝ පුස්තකාලයට).

ඔබ මයික්‍රොසොෆ්ට් විෂුවල් ස්ටුඩියෝ භාවිතා කරන්නේ නම්, ව්‍යාපෘති මඟින් .libගොනු ජනනය කරන බව ඔබට පෙනෙනු ඇත. මේවායේ අපනයනය කළ සංකේත වගුවක් සහ ආනයනික සංකේත වගුවක් අඩංගු වේ. ආනයනය කරන ලද සංකේත ඔබ සම්බන්ධ කරන පුස්තකාලවලට එරෙහිව විසඳනු ලබන අතර, අපනයනය කරන ලද සංකේත භාවිතා කරනු ලබන පුස්තකාල සඳහා ලබා දී ඇත .lib(ඇත්නම්).

වෙනත් සම්පාදකයින් / වේදිකා සඳහා සමාන යාන්ත්‍රණ පවතී.

පොදු වැරැද්ද පණිවිඩ error LNK2001, error LNK1120, error LNK2019සඳහා මයික්රොසොෆ්ට් විෂුවල් ස්ටුඩියෝ සහ undefined reference to symbolName සඳහා ගල්ෆ් .

කේතය:

struct X
{
   virtual void foo();
};
struct Y : X
{
   void foo() {}
};
struct A
{
   virtual ~A() = 0;
};
struct B: A
{
   virtual ~B(){}
};
extern int x;
void foo();
int main()
{
   x = 0;
   foo();
   Y y;
   B b;
}

GCC සමඟ පහත දෝෂ ජනනය කරනු ඇත :

/home/AbiSfw/ccvvuHoX.o: In function `main':
prog.cpp:(.text+0x10): undefined reference to `x'
prog.cpp:(.text+0x19): undefined reference to `foo()'
prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
collect2: ld returned 1 exit status

සහ Microsoft Visual Studio සමඟ සමාන දෝෂ :

1>test2.obj : error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
1>test2.obj : error LNK2001: unresolved external symbol "int x" (?x@@3HA)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?foo@X@@UAEXXZ)
1>...\test2.exe : fatal error LNK1120: 4 unresolved externals

පොදු හේතු අතර:


16
පුද්ගලිකව, මම සිතන්නේ එම්එස් සම්බන්ධක දෝෂ පණිවිඩ ජීසීසී දෝෂ තරම්ම කියවිය හැකි බවයි. නොවිසඳුනු බාහිර සඳහා අඹරන ලද සහ පාලනය නොකළ නම් ඇතුළත් කිරීමේ වාසිය ද ඔවුන්ට ඇත. ගැටලුව කුමක් දැයි බැලීමට ඔබට පුස්තකාල හෝ වස්තු ලිපිගොනු කෙලින්ම බැලීමට අවශ්‍ය වූ විට අඹරන ලද නමක් තිබීම ප්‍රයෝජනවත් වේ (නිදසුනක් ලෙස, ඇමතුම් සම්මුති නොගැලපීම). එසේම, එම්එස්වීසී හි කුමන අනුවාදයක් මෙහි දෝෂ ඇති කළේදැයි මට විශ්වාස නැත, නමුත් නව අනුවාදවල නොවිසඳුනු බාහිර සංකේතයට යොමු වන ශ්‍රිතයේ නම (අඹරන ලද සහ පාලනය නොකළ) ඇතුළත් වේ.
මයිකල් බර්

5
ඩේවිඩ් ඩ්‍රයිස්ඩේල් විසින් සම්බන්ධකයන් ක්‍රියා කරන ආකාරය ගැන හොඳ ලිපියක් ලිවීය: සම්බන්ධකයන් සඳහා ආරම්භක මාර්ගෝපදේශය . මෙම ප්‍රශ්නයේ මාතෘකාව අනුව, එය ප්‍රයෝජනවත් යැයි මම සිතුවෙමි.
ප්‍රෙස්කෝ

AnkTankorSmash gcc භාවිතා කරන්නද? MinGW වඩාත් නිවැරදිව කිව යුතුය.
doug65536

1
uch ලූචියන් ඔබ නිවැරදි එකතු කර ඉහත දෝෂ නිවැරදි කළහොත් හොඳයි
ෆල්ගුන්

179

පන්ති සාමාජිකයන්:

පිරිසිදු virtualවිනාශ කරන්නෙකුට ක්‍රියාත්මක කිරීමක් අවශ්‍ය වේ.

ඩිස්ට්‍රැක්ටර් පිරිසිදු යැයි ප්‍රකාශ කිරීම සඳහා ඔබට එය නිර්වචනය කිරීමට අවශ්‍ය වේ (සාමාන්‍ය ශ්‍රිතයක් මෙන් නොව):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

මෙය සිදුවන්නේ වස්තුව ව්‍යංගයෙන් විනාශ වූ විට මූලික පංති විනාශ කරන්නන් ලෙස හැඳින්වෙන නිසා අර්ථ දැක්වීමක් අවශ්‍ය වේ.

virtual ක්‍රම ක්‍රියාත්මක කළ යුතුය, නැතහොත් නිර්මල ලෙස අර්ථ දැක්විය යුතුය.

virtualනිර්වචනයක් නොමැති ක්‍රමවේදයන්ට මෙය සමාන වන අතර, පිරිසිදු ප්‍රකාශය ව්‍යාජ වෑටියක් ජනනය කරන අතර ශ්‍රිතය භාවිතා නොකර සම්බන්ධක දෝෂය ඔබට ලැබෙනු ඇත.

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

මෙය ක්‍රියාත්මක වීමට X::foo()නම් පිරිසිදු යැයි ප්‍රකාශ කරන්න :

struct X
{
    virtual void foo() = 0;
};

virtualපංති නොවන සාමාජිකයන්

සමහර සාමාජිකයන් පැහැදිලිව භාවිතා නොකළද අර්ථ දැක්විය යුතුය:

struct A
{ 
    ~A();
};

පහත දැක්වෙන්නේ දෝෂයකි:

A a;      //destructor undefined

පන්ති අර්ථ දැක්වීම තුළම ක්‍රියාත්මක කිරීම පේළිගත කළ හැකිය:

struct A
{ 
    ~A() {}
};

හෝ පිටත:

A::~A() {}

ක්‍රියාත්මක කිරීම පන්ති අර්ථ දැක්වීමෙන් පිටත නම්, නමුත් ශීර්ෂයක, inlineබහු අර්ථ දැක්වීමක් වැළැක්වීම සඳහා ක්‍රම සලකුණු කළ යුතුය .

භාවිතා කරන සියලුම සාමාජික ක්‍රම භාවිතා කරන්නේ නම් නිර්වචනය කළ යුතුය.

පොදු වැරැද්දක් නම් නම සුදුසුකම් ලැබීමට අමතක කිරීමයි:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

අර්ථ දැක්වීම විය යුතුය

void A::foo() {}

staticතනි පරිවර්තන ඒකකයකින් දත්ත සාමාජිකයින් පන්තියෙන් පිටත අර්ථ දැක්විය යුතුය :

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

static constපංති අර්ථ දැක්වීම තුළ සමෝධානික හෝ ගණන් කිරීමේ වර්ගයේ දත්ත සාමාජිකයෙකු සඳහා ආරම්භකයක් සැපයිය හැකිය ; කෙසේ වෙතත්, මෙම සාමාජිකයාගේ අමුතු භාවිතය සඳහා ඉහත විස්තර කර ඇති පරිදි නාම අවකාශ විෂය පථයේ අර්ථ දැක්වීමක් අවශ්‍ය වේ. C ++ 11 සියලුම static constදත්ත සාමාජිකයින් සඳහා පන්තිය තුළ ආරම්භ කිරීමට ඉඩ දෙයි .


දෙකම කිරීම කළ හැකි බව අවධාරණය කිරීමට ඔබට අවශ්‍ය යැයි සිතූ අතර, dtor ඇත්ත වශයෙන්ම ව්‍යතිරේකයක් නොවේ. (බැලූ බැල්මට එය ඔබේ වචන වලින් පැහැදිලි නොවේ.)
අඩුකිරීම

113

සුදුසු පුස්තකාල / වස්තු ලිපිගොනු සමඟ සම්බන්ධ වීමට අපොහොසත් වීම හෝ ක්‍රියාත්මක කිරීමේ ගොනු සම්පාදනය කිරීම

පොදුවේ ගත් කල, සෑම පරිවර්තන ඒකකයක්ම එම පරිවර්තන ඒකකයේ අර්ථ දක්වා ඇති සංකේතවල අර්ථ දැක්වීම් අඩංගු වස්තු ගොනුවක් ජනනය කරනු ඇත. එම සංකේත භාවිතා කිරීම සඳහා, ඔබ එම වස්තු ලිපිගොනු සමඟ සම්බන්ධ විය යුතුය.

Gcc යටතේ ඔබ විධාන රේඛාවේ එකට සම්බන්ධ කළ යුතු සියලුම වස්තු ගොනු නියම කරනු ඇත, නැතහොත් ක්‍රියාත්මක කිරීමේ ගොනු එකට සම්පාදනය කරන්න.

g++ -o test objectFile1.o objectFile2.o -lLibraryName

මෙම libraryNameමෙතන වේදිකාවක්-විශේෂිත එකතු තොරව, පුස්තකාලය පමණක් හිස් නාමය වේ. එබැවින් උදා: ලිනක්ස් පුස්තකාල ලිපිගොනු සාමාන්‍යයෙන් හැඳින්වුවද libfoo.soඔබ ලියන්නේ එය පමණි -lfoo. වින්ඩෝස් හි එම ගොනුවම හැඳින්විය හැක foo.lib, නමුත් ඔබ එකම තර්කය භාවිතා කරයි. ඔබට එම ගොනු භාවිතයෙන් සොයාගත හැකි නාමාවලිය එක් කිරීමට සිදු විය හැකිය -L‹directory›. පසු -lහෝ පසුව ඉඩක් ලිවීමට වග බලා ගන්න -L.

සඳහා XCode : -> පුස්තකාල සොයන්න පාත් එකතු -> ඇද ව්යාපෘතිය ෆෝල්ඩරයේ සැබෑ පුස්තකාල යොමු අතහැර පරිශීලක ශීර්ෂකය සොයන්න පථ එක් කරන්න.

MSVS යටතේ , ව්‍යාපෘතියකට එකතු කරන ලද ගොනු ස්වයංක්‍රීයව ඒවායේ වස්තු ලිපිගොනු එකට සම්බන්ධ කර ඇති අතර libගොනුවක් ජනනය වේ (පොදු භාවිතයේදී). වෙනම ව්‍යාපෘතියක සංකේත භාවිතා කිරීමට, ඔබට libව්‍යාපෘති සැකසුම් තුළ ගොනු ඇතුළත් කළ යුතුය. මෙය සිදු කරනු ලබන්නේ ව්‍යාපෘති ගුණාංගවල ලින්කර් කොටසේ ය Input -> Additional Dependencies. ( libගොනුව සඳහා මාර්ගය එක් කළ යුතුය Linker -> General -> Additional Library Directories) ගොනුවක් ලබා දී ඇති තෙවන පාර්ශවීය පුස්තකාලයක් භාවිතා කරන විට lib, එසේ කිරීමට අපොහොසත් වීම සාමාන්‍යයෙන් දෝෂයට හේතු වේ.

ගොනුව සම්පාදනයට එක් කිරීමට ඔබට අමතක වීම ද සිදුවිය හැකිය, එවැනි අවස්ථාවකදී වස්තු ගොනුව ජනනය නොවේ. දී gcc ඔබ විධාන රේඛාව තුල ඇති ගොනු එක් කරන්න කැමතියි. දී MSVS ගොනුව ව්යාපෘතිය එකතු එය (ගොනු වුවත්, අතින්, තනි තනිව ගොඩ නැඟීමට බැහැර කළ හැකි) ගිණුම ස්වංක්රීයව එය සකස් කර දෙනු ඇත.

වින්ඩෝස් ක්‍රමලේඛනයේදී, ඔබ අවශ්‍ය පුස්තකාලයක් සම්බන්ධ නොකළ බව පැවසීමේ ලකුණ වන්නේ නොවිසඳුනු සංකේතයේ නම ආරම්භ __imp_වීමයි. ප්‍රලේඛනයේ ඇති ශ්‍රිතයේ නම සොයා බලන්න, එවිට ඔබ භාවිතා කළ යුත්තේ කුමන පුස්තකාලයද යන්න එහි සඳහන් විය යුතුය. උදාහරණයක් ලෙස, MSDN විසින් එක් එක් ශ්‍රිතයේ පතුලේ ඇති කොටුවක තොරතුරු “පුස්තකාලය” යනුවෙන් හැඳින්වෙන කොටසක තබයි.


1
gcc main.cවෙනුවට පොදු වැරැද්ද ඔබට පැහැදිලිව ආවරණය කළ හැකි නම් හොඳයි gcc main.c other.c (.o ගොනු සෑදීමට තරම් ඔවුන්ගේ ව්‍යාපෘති විශාල වීමට පෙර ආරම්භකයින් බොහෝ විට කරන්නේ).
එම්එම්

101

ප්‍රකාශ කළ නමුත් විචල්‍යයක් හෝ ශ්‍රිතයක් නිර්වචනය කර නැත.

සාමාන්‍ය විචල්‍ය ප්‍රකාශයකි

extern int x;

මෙය ප්‍රකාශයක් පමණක් බැවින් තනි අර්ථ දැක්වීමක් අවශ්‍ය වේ. අනුරූප අර්ථ දැක්වීමක් වනුයේ:

int x;

උදාහරණයක් ලෙස, පහත දැක්වෙන්නේ දෝෂයක් ජනනය කරයි:

extern int x;
int main()
{
    x = 0;
}
//int x; // uncomment this line for successful definition

කාර්යයන් සඳහා සමාන අදහස් අදාළ වේ. ශ්‍රිතයක් නිර්වචනය නොකර එය ප්‍රකාශ කිරීම දෝෂයට තුඩු දෙයි:

void foo(); // declaration only
int main()
{
   foo();
}
//void foo() {} //uncomment this line for successful definition

ඔබ ක්‍රියාත්මක කරන කාර්යය ඔබ ප්‍රකාශ කළ ක්‍රියාවට හරියටම ගැලපෙන බවට වග බලා ගන්න. උදාහරණයක් ලෙස, ඔබට නොගැලපෙන cv- සුදුසුකම් තිබිය හැකිය:

void foo(int& x);
int main()
{
   int x;
   foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
                          //for void foo(int& x)
                          

නොගැලපීම් සඳහා වෙනත් උදාහරණ ඇතුළත් වේ

  • එක් නාම අවකාශයක ප්‍රකාශිත ශ්‍රිතය / විචල්‍යය, තවත් තැනක අර්ථ දක්වා ඇත.
  • පන්ති සාමාජිකයෙකු ලෙස ප්‍රකාශයට පත් කරන ලද ශ්‍රිතය / විචල්‍යය ගෝලීය (හෝ අනෙක් අතට) ලෙස අර්ථ දක්වා ඇත.
  • ක්‍රියාකාරී ප්‍රතිලාභ වර්ගය, පරාමිති අංකය සහ වර්ග සහ ඇමතුම් සම්මුතිය සියල්ලම හරියටම එකඟ නොවේ.

සම්පාදකයාගේ දෝෂ පණිවිඩය බොහෝ විට ප්‍රකාශිත නමුත් කිසි විටෙක නිර්වචනය නොකළ විචල්‍යය හෝ ශ්‍රිතය පිළිබඳ සම්පූර්ණ ප්‍රකාශය ඔබට ලබා දෙනු ඇත. ඔබ ලබා දුන් අර්ථ දැක්වීමට එය සමීපව සසඳන්න. සෑම විස්තරයක්ම ගැලපෙන බවට වග බලා ගන්න.


වීඑස් හි, මූලාශ්‍ර නාමාවලියට එකතු#includes නොකළ ශීර්ෂයට ගැලපෙන සීපීපී ගොනු ද නැතිවූ අර්ථ දැක්වීම් ගණයට අයත් වේ.
ලෝරි ස්ටීර්න්

87

එකිනෙකට පරායත්ත සම්බන්ධිත පුස්තකාල නියම කර ඇති අනුපිළිවෙල වැරදිය.

පුස්තකාල එකිනෙකට රඳා පවතින්නේ නම් පුස්තකාල සම්බන්ධ වන අනුපිළිවෙල වැදගත් වේ. පොදුවේ ගත් කල, පුස්තකාලය පුස්තකාලය Aමත රඳා පවතී නම් B, ඊට පෙර සම්බන්ධක ධජවල දිස්විය libA යුතුයlibB .

උදාහරණයක් වශයෙන්:

// B.h
#ifndef B_H
#define B_H

struct B {
    B(int);
    int x;
};

#endif

// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}

// A.h
#include "B.h"

struct A {
    A(int x);
    B b;
};

// A.cpp
#include "A.h"

A::A(int x) : b(x) {}

// main.cpp
#include "A.h"

int main() {
    A a(5);
    return 0;
};

පුස්තකාල සාදන්න:

$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o 
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o 
ar: creating libB.a
a - B.o

සම්පාදනය කරන්න:

$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out

ඒ නිසා නැවත වරක් නැවත නැවත කිරීමට, නියෝගය වේද කාරණය!


මට කුතුහලය දනවන කරුණ නම් මගේ නඩුවේ හවුල් පුස්තකාලයක් මත රඳා පවතින එක් වස්තු ගොනුවක් තිබීමයි. මම Makefile කිරීමට, වෙනස් කිරීමට සහ පුස්තකාලය කිරීමට සිදු වුණා පසු Debian මත gcc 4.8.4 සමඟ වස්තුව. සෙන්ටෝස් 6.5 හි gcc 4.4 සමඟ Makefile කිසිදු ගැටළුවක් නොමැතිව ක්‍රියා කළේය.
මාකෝ සුල්ලා

74

"නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේතය" යනු කුමක්ද?

"නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේතය" යනු කුමක්දැයි පැහැදිලි කිරීමට මම උත්සාහ කරමි.

සටහන: මම g ++ සහ ලිනක්ස් භාවිතා කරන අතර සියලු උදාහරණ ඒ සඳහා වේ

උදාහරණයක් ලෙස අපට කේතයක් තිබේ

// src1.cpp
void print();

static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;

int main()
{
    print();
    return 0;
}

සහ

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
//extern int local_var_name;

void print ()
{
    // printf("%d%d\n", global_var_name, local_var_name);
    printf("%d\n", global_var_name);
}

වස්තු ගොනු සාදන්න

$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o

එකලස් කිරීමේ අදියරෙන් පසු අප සතුව වස්තු ගොනුවක් ඇත, එහි අපනයනය සඳහා ඕනෑම සංකේත අඩංගු වේ. සංකේත දෙස බලන්න

$ readelf --symbols src1.o
  Num:    Value          Size Type    Bind   Vis      Ndx Name
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL14local_var_name # [1]
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_var_name     # [2]

ප්‍රතිදානයෙන් සමහර පේළි මම ප්‍රතික්ෂේප කර ඇත්තෙමි

එබැවින්, අපනයනය සඳහා පහත දැක්වෙන සංකේත අපට පෙනේ.

[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable

src2.cpp කිසිවක් අපනයනය නොකරන අතර එහි සංකේත කිසිවක් අප දැක නැත

අපගේ වස්තු ගොනු සම්බන්ධ කරන්න

$ g++ src1.o src2.o -o prog

එය ක්‍රියාත්මක කරන්න

$ ./prog
123

ලින්කර් අපනයනය කළ සංකේත දැක එය සම්බන්ධ කරයි. දැන් අපි මෙහි මෙන් src2.cpp හි රේඛා නොගැලපීමට උත්සාහ කරමු

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
extern int local_var_name;

void print ()
{
    printf("%d%d\n", global_var_name, local_var_name);
}

වස්තු ගොනුවක් නැවත ගොඩනඟන්න

$ g++ -c src2.cpp -o src2.o

හරි (දෝෂ නැත), අපි වස්තු ගොනුවක් පමණක් සාදන නිසා, සම්බන්ධ කිරීම තවමත් සිදු කර නොමැත. සම්බන්ධ කිරීමට උත්සාහ කරන්න

$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status

එය සිදුවී ඇත්තේ අපගේ local_var_name ස්ථිතික නිසා, එනම් එය වෙනත් මොඩියුල සඳහා නොපෙනේ. දැන් වඩාත් ගැඹුරින්. පරිවර්තන අදියර ප්‍රතිදානය ලබා ගන්න

$ g++ -S src1.cpp -o src1.s

// src1.s
look src1.s

    .file   "src1.cpp"
    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4
    .globl  global_var_name
    .data
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; assembler code, not interesting for us
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

එබැවින්, local_var_name සඳහා ලේබලයක් නොමැති බව අපි දැක ඇත්තෙමු, ඒ නිසා සම්බන්ධකය එය සොයා නොගත්තේය. නමුත් අපි හැකර්වරු :) අපට එය නිවැරදි කළ හැකිය. ඔබේ පෙළ සංස්කාරකයේ src1.s විවෘත කර වෙනස් කරන්න

.local  _ZL14local_var_name
.comm   _ZL14local_var_name,4,4

වෙත

    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789

එනම් ඔබට පහත පරිදි තිබිය යුතුය

    .file   "src1.cpp"
    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789
    .globl  global_var_name
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; ...

අපි local_var_name හි දෘශ්‍යතාව වෙනස් කර එහි අගය 456789 ලෙස සකසා ඇත. එයින් වස්තු ගොනුවක් තැනීමට උත්සාහ කරන්න

$ g++ -c src1.s -o src2.o

හරි, කියවීමේ ප්‍රතිදානය බලන්න (සංකේත)

$ readelf --symbols src1.o
8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 local_var_name

දැන් local_var_name හි බන්ධන GLOBAL ඇත (LOCAL විය)

සබැඳිය

$ g++ src1.o src2.o -o prog

එය ක්‍රියාත්මක කරන්න

$ ./prog 
123456789

හරි, අපි එය හැක් කරනවා :)

එබැවින්, ප්‍රති result ලයක් ලෙස - වස්තු ලිපිගොනු තුළ සම්බන්ධකයට ගෝලීය සංකේත සොයාගත නොහැකි වූ විට “නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂයක්” සිදු වේ.


71

සංකේත C වැඩසටහනක අර්ථ දක්වා ඇති අතර C ++ කේතයේ භාවිතා කරන ලදී.

ශ්‍රිතය (හෝ විචල්‍යය) void foo()සී වැඩසටහනක අර්ථ දක්වා ඇති අතර ඔබ එය සී ++ වැඩසටහනක භාවිතා කිරීමට උත්සාහ කරයි:

void foo();
int main()
{
    foo();
}

C ++ සම්බන්ධකය මඟින් නම් අඹරනු ඇතැයි අපේක්ෂා කරයි, එබැවින් ඔබ ශ්‍රිතය මෙසේ ප්‍රකාශ කළ යුතුය:

extern "C" void foo();
int main()
{
    foo();
}

ඒ හා සමානව, C වැඩසටහනක අර්ථ දැක්වීම වෙනුවට, ශ්‍රිතය (හෝ විචල්‍යය) void foo()C ++ වලින් අර්ථ දක්වා ඇති නමුත් C සම්බන්ධතාවය සමඟ:

extern "C" void foo();

ඔබ එය C ++ සම්බන්ධතාවයක් සහිත C ++ වැඩසටහනක භාවිතා කිරීමට උත්සාහ කරයි.

සම්පූර්ණ පුස්තකාලයක් ශීර්ෂ ගොනුවකට ඇතුළත් කර ඇත්නම් (එය සී කේතය ලෙස සම්පාදනය කරන ලදි); ඇතුළත් කිරීම පහත පරිදි විය යුතුය;

extern "C" {
    #include "cheader.h"
}

5
හෝ ඊට ප්‍රතිවිරුද්ධව, ඔබ සී පුස්තකාලයක් සංවර්ධනය කරන්නේ නම්, හොඳ රීතියක් නම්, අපනයනය කරන ලද සියලුම ප්‍රකාශයන් සමඟ ( #ifdef __cplusplus [\n] extern"C" { [\n] #endifසහ සැබෑ කරත්ත ආපසු පැමිණීම ) සහ ශීර්ෂ ගොනුව (ය) ආරක්ෂා කර ගැනීමයි . #ifdef __cplusplus [\n] } [\n] #endif[\n]
බෙන්ටෝයි 13

ඉහත අදහස් දැක්වීමේදී මෙන්, මෙහි 'මිශ්‍ර-භාෂා ශීර්ෂයන්
zanbri

ඇත්තටම මට උදව් කළා! මම මෙම ප්‍රශ්නය සොයන විට මෙය මගේ නඩුවයි
නයිට්ෆොරිසන්

ඔබ ඔබේ සාමාන්ය C ++ වට අහම්බෙන් ශීර්ෂ ගොනුව ඇතුළත් නම් මෙය ද සිදු කළ හැකි extern සී : extern "C" { #include <myCppHeader.h> }.
ComFreek

68

අනෙක් සියල්ල අසමත් වුවහොත් නැවත සකස් කරන්න.

විෂුවල් ස්ටුඩියෝ 2012 හි නොවිසඳුණු බාහිර දෝෂයක් ඉවත් කිරීමට මට මෑතකදී හැකි වූයේ වැරදි කළ ගොනුව නැවත සකස් කිරීමෙනි. මම නැවත ගොඩනඟන විට දෝෂය පහව ගියේය.

මෙය සාමාන්‍යයෙන් සිදුවන්නේ පුස්තකාල දෙකක් (හෝ වැඩි ගණනක්) චක්‍රීය යැපීමක් ඇති විටය. පුස්තකාලය B.lib සහ පුස්තකාල B හි සංකේත භාවිතා කිරීමට උත්සාහ කරයි A.lib වෙතින් සංකේත භාවිතා කිරීමට උත්සාහ කරයි. ආරම්භ කිරීමට දෙකම නොපවතී. ඔබ A සම්පාදනය කිරීමට උත්සාහ කරන විට, B.lib සොයාගත නොහැකි නිසා සම්බන්ධක පියවර අසාර්ථක වේ. A.lib ජනනය වනු ඇත, නමුත් dll නැත. එවිට ඔබ B සම්පාදනය කරයි, එය සාර්ථක වන අතර B.lib ජනනය කරයි. A නැවත සම්පාදනය කිරීම දැන් ක්‍රියාත්මක වන්නේ B.lib දැන් සොයාගෙන ඇති බැවිනි.


1
නිවැරදි - පුස්තකාලවල චක්‍රීය යැපීමක් ඇති විට මෙය සිදු වේ.
ලුචියන් ග්‍රිගෝර්

1
මම ඔබේ පිළිතුර පුළුල් කර ප්‍රධාන පිළිතුරට සම්බන්ධ කළෙමි. ස්තූතියි.
ලුචියන් ග්‍රිගෝර්

58

මොඩියුල / ඩීඑල් (සම්පාදක විශේෂිත) හරහා වැරදි ලෙස ආනයනය / අපනයන ක්‍රම / පන්ති.

MSVS භාවිතා අපනයන හා ආනයන කිරීමට වූ සංකේත නියම කිරීමට ඔබ අවශ්ය __declspec(dllexport)හා__declspec(dllimport) .

මෙම ද්විත්ව ක්‍රියාකාරිත්වය සාමාන්‍යයෙන් ලබා ගන්නේ සාර්ව භාවිතයෙන් ය:

#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif

සාර්ව THIS_MODULEඅර්ථ දැක්වෙන්නේ ශ්‍රිතය අපනයනය කරන මොඩියුලය තුළ පමණි. ඒ ආකාරයෙන්, ප්‍රකාශය:

DLLIMPEXP void foo();

දක්වා පුළුල් වේ

__declspec(dllexport) void foo();

වත්මන් මොඩියුලය එහි අර්ථ දැක්වීම අඩංගු බැවින් ශ්‍රිතය අපනයනය කිරීමට සම්පාදකයාට පවසයි. ප්‍රකාශය වෙනත් මොඩියුලයකට ඇතුළත් කළ විට එය පුළුල් වේ

__declspec(dllimport) void foo();

නිර්වචනය ඔබ සම්බන්ධ කළ එක් පුස්තකාලයක ඇති බව සම්පාදකයාට පවසයි ( 1 ද බලන්න ) ).

ඔබට ආනයන / අපනයන පන්ති සමාන කළ හැකිය:

class DLLIMPEXP X
{
};

2
සම්පුර්ණ වීමට නම්, මෙම පිළිතුරෙහි GCC visibilityසහ වින්ඩෝස් .defගොනු සඳහන් කළ යුතුය , මේවා සංකේත නාමයට සහ පැවැත්මට ද බලපෑම් කරයි.
rubenvb

@rubenvb මම .defඅවුරුදු ගණනාවක් තිස්සේ ලිපිගොනු භාවිතා කර නැත . පිළිතුරක් එක් කිරීමට හෝ මෙය සංස්කරණය කිරීමට නිදහස් වන්න.
ලුචියන් ග්‍රිගෝර්

57

සැකිලි ක්‍රියාත්මක කිරීම් නොපෙනේ.

විශේෂීකරණය නොකළ සැකිලි ඒවායේ අර්ථ දැක්වීම් ඒවා භාවිතා කරන සියලුම පරිවර්තන ඒකකවලට දැකිය යුතුය. එයින් අදහස් කරන්නේ ඔබට අච්චුවක අර්ථ දැක්වීම ක්‍රියාත්මක කිරීමේ ගොනුවකට වෙන් කළ නොහැකි බවයි. ඔබ ක්‍රියාත්මක කිරීම වෙන් කළ යුතු නම්, සාමාන්‍ය විසඳුම වන්නේ implඅච්චුව ප්‍රකාශ කරන ශීර්ෂයේ අවසානයේ ඔබ ඇතුළත් කරන ගොනුවක් තිබීමයි. පොදු තත්වයක් නම්:

template<class T>
struct X
{
    void foo();
};

int main()
{
    X<int> x;
    x.foo();
}

//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}

මෙය නිවැරදි කිරීම සඳහා, ඔබ අර්ථ දැක්වීම X::fooශීර්ෂ ගොනුවට හෝ එය භාවිතා කරන පරිවර්තන ඒකකයට පෙනෙන ස්ථානයකට ගෙන යා යුතුය .

විශේෂිත සැකිලි ක්‍රියාත්මක කිරීමේ ගොනුවක ක්‍රියාත්මක කළ හැකි අතර ක්‍රියාත්මක කිරීම දෘශ්‍යමාන විය යුතු නැත, නමුත් විශේෂීකරණය කලින් ප්‍රකාශයට පත් කළ යුතුය.

වැඩිදුර පැහැදිලි කිරීම සහ තවත් විසඳුමක් සඳහා (පැහැදිලි ක්ෂණිකකරණය) මෙම ප්‍රශ්නය සහ පිළිතුර බලන්න .


1
"සැකිලි ශීර්ෂය තුළ අර්ථ දැක්විය යුතුය" සඳහා වැඩිදුර තොරතුරු stackoverflow.com/questions/495021
PlasmaHH

57

මෙය සෑම VC ++ ක්‍රමලේඛකයෙක්ම කාලය හා වේලාව නැවත දැක ඇති ව්‍යාකූල දෝෂ පණිවිඩ වලින් එකකි. අපි මුලින්ම කරුණු පැහැදිලි කර ගනිමු.

පිළිතුර - සංකේතය යනු කුමක්ද? කෙටියෙන් කිවහොත්, සංකේතයක් යනු නමකි. එය විචල්‍ය නාමයක්, ශ්‍රිත නාමයක්, පන්ති නාමයක්, යතුරු ලියනය කළ නමක් හෝ සී ++ භාෂාවට අයත් නම් සහ සං signs ා හැර වෙනත් දෙයක් විය හැකිය. එය පරිශීලක පරායත්ත පුස්තකාලයක් මගින් නිර්වචනය කර හෝ හඳුන්වා දී ඇත (තවත් පරිශීලක අර්ථ දැක්වීමක්).

B. බාහිර යනු කුමක්ද? VC ++ හි, සෑම ප්‍රභව ගොනුවක්ම (.cpp, .c, ආදිය) පරිවර්තන ඒකකයක් ලෙස සලකනු ලැබේ, සම්පාදකයා වරකට එක් ඒකකයක් සම්පාදනය කරයි, සහ වර්තමාන පරිවර්තන ඒකකය සඳහා එක් වස්තු ගොනුවක් (.obj) ජනනය කරයි. (මෙම ප්‍රභව ගොනුව ඇතුළත් කර ඇති සෑම ශීර්ෂ ගොනුවක්ම පෙර සැකසූ බවත් මෙම පරිවර්තන ඒකකයේ කොටසක් ලෙස සලකනු ඇති බවත් සලකන්න) පරිවර්තන ඒකකයක් තුළ ඇති සියල්ල අභ්‍යන්තර ලෙස සලකනු ලැබේ, අනෙක් සියල්ල බාහිර ලෙස සැලකේ. C ++, ඔබ වැනි මූල පද භාවිතා කරමින් බාහිර සංකේතයක් අදාල විය හැක extern, __declspec (dllimport)සහ යනාදි.

C. “අධිෂ්” ානය ”යනු කුමක්ද? විසඳීම යනු සම්බන්ධක-කාලීන යෙදුමකි. සම්බන්ධක වේලාවේදී, සම්බන්ධකය එහි සංකේතය අභ්‍යන්තරව සොයාගත නොහැකි වස්තු ලිපිගොනු වල සෑම සංකේතයක් සඳහාම බාහිර අර්ථ දැක්වීම සොයා ගැනීමට උත්සාහ කරයි. මෙම සෙවීමේ ක්‍රියාවලියේ විෂය පථය:

  • කාලය සම්පාදනය කිරීමේදී ජනනය කරන ලද සියලුම වස්තු ගොනු
  • මෙම ගොඩනැගිලි යෙදුමේ අතිරේක පරායත්තයන් ලෙස පැහැදිලිව හෝ ව්‍යංගයෙන් නිශ්චිතව දක්වා ඇති සියලුම පුස්තකාල (.lib).

මෙම සෙවීමේ ක්‍රියාවලිය විසදුම ලෙස හැඳින්වේ.

D. අවසාන වශයෙන්, නොවිසඳුනු බාහිර සංකේතය ඇයි? අභ්‍යන්තරව අර්ථ දැක්වීමක් නොමැති සංකේතයක් සඳහා සම්බන්ධකයට බාහිර අර්ථ දැක්වීම සොයාගත නොහැකි නම්, එය නොවිසඳුනු බාහිර සංකේත දෝෂයක් වාර්තා කරයි.

E. LNK2019 සඳහා විය හැකි හේතු : නොවිසඳුනු බාහිර සංකේත දෝෂයකි. මෙම දෝෂය සම්බන්ධකය බාහිර සංකේතවල අර්ථ දැක්වීම සොයා ගැනීමට අපොහොසත් වීම නිසා බව අපි දැනටමත් දනිමු, විය හැකි හේතු පහත පරිදි වර්ග කළ හැකිය:

  1. අර්ථ දැක්වීම පවතී

උදාහරණයක් ලෙස, අපට a.cpp හි අර්ථ දක්වා ඇති foo නම් ශ්‍රිතයක් තිබේ නම්:

int foo()
{
    return 0;
}

B.cpp හි අපට ශ්‍රිතය foo ලෙස හැඳින්වීමට අවශ්‍ය බැවින් අපි එකතු කරමු

void foo();

foo () ශ්‍රිතය ප්‍රකාශ කිරීමට සහ එය වෙනත් ශ්‍රිත ආයතනයකට අමතන්න bar():

void bar()
{
    foo();
}

දැන් ඔබ මෙම කේතය ගොඩනඟන විට foo නොවිසඳුනු සංකේතයක් බවට පැමිණිලි කරමින් ඔබට LNK2019 දෝෂයක් ලැබෙනු ඇත. මෙම අවස්ථාවෙහිදී, foo () හි අර්ථ දැක්වීම a.cpp හි ඇති බව අපි දනිමු, නමුත් අප අමතන ක්‍රමයට වඩා වෙනස් (වෙනස් ප්‍රතිලාභ අගය). අර්ථ දැක්වීම පවතින අවස්ථාව මෙයයි.

  1. අර්ථ දැක්වීම නොපවතී

අපට පුස්තකාලයක සමහර කාර්යයන් ඇමතීමට අවශ්‍ය නම්, නමුත් ආනයන පුස්තකාලය Project | Properties | Configuration Properties | Linker | Input | Additional Dependencyඔබේ ව්‍යාපෘති සැකසුමෙහි අතිරේක පරායත්තතා ලැයිස්තුවට (:) සිට සකසා ඇත ) එකතු නොවේ . වර්තමාන සෙවුම් විෂය පථය තුළ අර්ථ දැක්වීම නොපවතින බැවින් දැන් සම්බන්ධකය LNK2019 වාර්තා කරයි.


1
ක්රමානුකූල පැහැදිලි කිරීම සඳහා ස්තූතියි. මෙය කියවීමෙන් පසු මට මෙහි අනෙක් පිළිතුරු තේරුම් ගත හැකිය.
displayName

41

නිර්වචනය නොකළ WinMain@16හෝ ඊට සමාන 'අසාමාන්‍ය' main() පිවිසුම් ලක්ෂ්‍ය යොමුව (විශේෂයෙන්).

ඔබගේ සත්‍ය IDE සමඟ නිවැරදි ව්‍යාපෘති වර්ගය තෝරා ගැනීමට ඔබට මග හැරී ඇත. බහුලව භාවිතා වන int main(int argc, char** argv);අත්සන වෙනුවට වින්ඩෝස් යෙදුම් ව්‍යාපෘති එවැනි පිවිසුම් ලක්ෂ්‍ය ශ්‍රිතයට (ඉහත අස්ථානගතව ඇති සඳහනෙහි දක්වා ඇති පරිදි) බැඳීමට IDE ට අවශ්‍ය විය හැකිය .

ඔබේ IDE සරල කොන්සෝල ව්‍යාපෘති සඳහා සහය දක්වන්නේ නම් , වින්ඩෝස් යෙදුම් ව්‍යාපෘතියක් වෙනුවට මෙම ව්‍යාපෘති වර්ගය තෝරා ගැනීමට ඔබට අවශ්‍ය විය හැකිය.


මෙන්න case1 සහ case2සැබෑ ලෝක ගැටලුවකින් වඩාත් විස්තරාත්මකව හසුරුවන .


2
උදව් කිරීමට නොහැකි නමුත් මෙම ප්‍රශ්නය සහ මෙය බොහෝ විට සිදුවන්නේ ප්‍රධාන කාර්යයක් නොමැති වීම නිසාය WinMain. වලංගු C ++ වැඩසටහන් සඳහා a අවශ්‍ය වේ main.
chris

36

ඔබ තෙවන පාර්ශවීය පුස්තකාල භාවිතා කරන්නේ නම් ඔබට නිවැරදි 32/64 බිට් ද්විමය ඇති බවට වග බලා ගන්න


34

#pragmaසම්බන්ධක වේලාවේදී නිවැරදි පුස්තකාලය යොමු කිරීමට මයික්‍රොසොෆ්ට් ඉදිරිපත් කරයි ;

#pragma comment(lib, "libname.lib")

පුස්තකාලයේ නාමාවලිය ඇතුළු පුස්තකාල මාර්ගයට අමතරව මෙය පුස්තකාලයේ සම්පූර්ණ නම විය යුතුය.


34

නව මෙවලම් කට්ටල අනුවාදය සඳහා දෘශ්‍ය ස්ටුඩියෝ නුජෙට් පැකේජය යාවත්කාලීන කළ යුතුය

මට මේ ගැටලුව තිබුනේ විෂුවල් ස්ටුඩියෝ 2013 සමඟ libpng සම්බන්ධ කිරීමට උත්සාහ කිරීමෙනි. ගැටළුව වන්නේ පැකේජ ගොනුවේ තිබුණේ විෂුවල් ස්ටුඩියෝ 2010 සහ 2012 සඳහා පුස්තකාල පමණි.

නිවැරදි විසඳුම නම් සංවර්ධකයා විසින් යාවත්කාලීන කරන ලද පැකේජයක් නිකුත් කර යාවත්කාලීන කරනු ඇතැයි අපේක්ෂා කිරීමයි, නමුත් එය VS2013 සඳහා අතිරේක සැකසුමක අනවසරයෙන් ඇතුළුවී VS2012 පුස්තකාල ලිපිගොනු වෙත යොමු කිරීම මට වැඩ කළේය.

මම පැකේජය සංස්කරණය කළේ ( packagesවිසඳුමේ නාමාවලිය තුළ ඇති ෆෝල්ඩරයේ) packagename\build\native\packagename.targetsඑම ගොනුව සොයා ගැනීමෙන් සහ ඇතුළත, සියලුම v110කොටස් පිටපත් කිරීමෙනි . මම වෙනස් v110කිරීමට v120ඇති තත්ත්වය ක්ෂේත්ර පමණක් සියලු ලෙස ගොනු නාමය මාර්ග හැර ඉතා ප්රවේසම් වීම v110. මෙය හුදෙක් විෂුවල් ස්ටුඩියෝ 2013 සඳහා 2012 සඳහා පුස්තකාල සමඟ සම්බන්ධ වීමට ඉඩ දී ඇති අතර මේ අවස්ථාවේ දී එය ක්‍රියාත්මක විය.


1
මෙය ඕනෑවට වඩා විශේෂිත යැයි පෙනේ - සමහර විට නව නූලක් මෙම පිළිතුර සඳහා වඩා හොඳ ස්ථානයක් වනු ඇත.
ලුචියන් ග්‍රිගෝර්

3
Uch ලූචියන් ග්‍රිගෝර්: මට මෙහි පළ කිරීමට අවශ්‍ය වූයේ එම ප්‍රශ්නය හරියටම මෙම ප්‍රශ්නය වන නමුත් එය මෙම ප්‍රශ්නයේ අනුපිටපතක් ලෙස සලකුණු කර ඇති බැවින් මට එහි පිළිතුරු දීමට නොහැකි විය. ඒ නිසා මම ඒ වෙනුවට මගේ පිළිතුර මෙහි පළ කළා.
මල්වීනියස්

එම ප්‍රශ්නයට දැනටමත් පිළිගත් පිළිතුරක් ඇත. පොදු හේතුව ඉහත ලැයිස්තුගත කර ඇති නිසා එය අනුපිටපතක් ලෙස සලකුණු කර ඇත. ඇතුළත් කර නොමැති පුස්තකාලයක ඇති සෑම ගැටලුවකටම අපට පිළිතුරක් ඇත්නම් කුමක් සිදුවේද?
ලුචියන් ග්‍රිගෝර්

6
Uch ලූචියන් ග්‍රිගෝර්: මෙම ගැටළුව පුස්තකාලයකට විශේෂිත නොවේ, එය දෘශ්‍ය ස්ටුඩියෝ හි පැකේජ කළමනාකරණ පද්ධතිය භාවිතා කරන සියලුම පුස්තකාලවලට බලපායි. මට අනෙක් ප්‍රශ්නය සොයා ගැනීමට සිදු වූයේ අප දෙදෙනාට libpng සමඟ ගැටලු ඇති බැවිනි. මට libxml2, libiconv සහ glew සඳහා එකම ගැටළුව (එකම විසඳුම සමඟ) තිබුණි. එම ප්‍රශ්නය විෂුවල් ස්ටුඩියෝ හි පැකේජ කළමණාකරණ පද්ධතියේ ඇති ගැටළුවක් වන අතර, මගේ පිළිතුර එයට හේතුව පැහැදිලි කර විසඳුමක් සපයයි. කවුරුහරි "නොවිසඳුනු බාහිර" දුටු අතර එය ඇත්ත වශයෙන්ම පැකේජ කළමනාකරණ ගැටළුවක් වන විට එය සම්මත සම්බන්ධක ගැටලුවක් යැයි උපකල්පනය කළේය.
මල්වීනියස්

34

ඔබ සතුව c ++ හි ලියා ඇති විශාල ව්‍යාපෘතියක් තිබේ. එහි .cpp ගොනු දහසක් සහ .h ගොනු දහසක් ඇත. තවද අපි කියමු ව්‍යාපෘතිය ස්ථිතික පුස්තකාල දහයක් මත රඳා පවතී. අපි කියමු අපි වින්ඩෝස් වල සිටින අතර අපගේ ව්‍යාපෘතිය විෂුවල් ස්ටුඩියෝ 20xx හි ගොඩනඟමු. සම්පූර්ණ විසඳුම සම්පාදනය කිරීම ආරම්භ කිරීම සඳහා ඔබ Ctrl + F7 විෂුවල් ස්ටුඩියෝව එබූ විට (අපට විසඳුමේ ඇත්තේ එක් ව්‍යාපෘතියක් යැයි සිතමු)

සම්පාදනය කිරීමේ තේරුම කුමක්ද?

  • .Vcxproj ගොනුවට දෘශ්‍ය ස්ටුඩියෝ සෙවීම සහ .cpp දිගුව ඇති සෑම ගොනුවක්ම සම්පාදනය කිරීම ආරම්භ කරන්න. සම්පාදනය කිරීමේ අනුපිළිවෙල නිර්වචනය කර නැත. එබැවින් main.cpp ගොනුව මුලින්ම සම්පාදනය කර ඇතැයි ඔබ නොසිතිය යුතුය
  • .Cpp ලිපිගොනු අතිරේක .h ගොනු මත රඳා පවතී නම් .cpp ගොනුවේ අර්ථ දැක්විය හැකි හෝ නොවිය හැකි සංකේත සොයා ගැනීමට.
  • සම්පාදකයාට එක් සංකේතයක් සොයාගත නොහැකි වූ .cpp ගොනුවක් තිබේ නම්, සම්පාදක කාල දෝෂයක් මඟින් පණිවිඩය මතු කරයි සංකේතය x සොයාගත නොහැකි විය
  • .Cpp දිගුව සහිත සෑම ගොනුවක් සඳහාම වස්තු ගොනුවක් ජනනය වේ .o මෙන්ම විෂුවල් ස්ටුඩියෝ විසින් ප්‍රතිදානය ලියන්නේ ProjectName.Cpp.Clean.txt නම් ගොනුවක වන අතර එහි සියලුම වස්තු ලිපිගොනු අඩංගු වේ.

සම්පාදනය කිරීමේ දෙවන පියවර ලින්කර් විසින් සිදු කරනු ලැබේ. ලින්කර් විසින් සියලු වස්තු ගොනුව ඒකාබද්ධ කොට අවසානයේ ප්‍රතිදානය ගොඩනගා ගත යුතුය (එය ක්‍රියාත්මක කළ හැකි හෝ පුස්තකාලයක් විය හැකිය)

ව්‍යාපෘතියක් සම්බන්ධ කිරීමේ පියවර

  • සියලුම වස්තු ලිපිගොනු විග්‍රහ කර ශීර්ෂයන්හි පමණක් ප්‍රකාශයට පත් කර ඇති අර්ථ දැක්වීම සොයා ගන්න (උදා: පෙර පිළිතුරු වල සඳහන් පරිදි පන්තියක එක් ක්‍රමයක කේතය, හෝ පන්තියක් තුළ සාමාජික වන ස්ථිතික විචල්‍යයක් ආරම්භ කිරීම සිදුවුවහොත්)
  • වස්තු ලිපිගොනු වල එක් සංකේතයක් සොයාගත නොහැකි නම් ඔහු අතිරේක පුස්තකාලවල ද සොයනු ඇත. ව්‍යාපෘතියකට නව පුස්තකාලයක් එක් කිරීම සඳහා වින්‍යාස ගුණාංග -> VC ++ නාමාවලි -> පුස්තකාල නාමාවලි සහ මෙහි ඔබ පුස්තකාල සහ වින්‍යාස ගුණාංග සෙවීම සඳහා අතිරේක ෆෝල්ඩරයක් නියම කර ඇත -> ලින්කර් -> පුස්තකාලයේ නම සඳහන් කිරීම සඳහා ආදානය . -If මෙම Linker ඔබ එක් .cpp ලියන්න ඇති ඔහු මතු සංකේතය සොයාගත නොහැකි විය linker කාලය දෝෂයක් වගේ විය හැකි error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)

නිරීක්ෂණය

  1. ලින්කර් එක් සංකේතයක් සොයාගත් පසු ඔහු ඒ සඳහා වෙනත් පුස්තකාලවල සොයන්නේ නැත
  2. පුස්තකාල සම්බන්ධ කිරීමේ අනුපිළිවෙල වැදගත් වේ.
  3. එක් ස්ථිතික පුස්තකාලයක ලින්කර් බාහිර සංකේතයක් සොයා ගන්නේ නම්, ඔහු ව්‍යාපෘතියේ ප්‍රතිදානයේ සංකේතය ඇතුළත් කරයි. කෙසේ වෙතත්, පුස්තකාලය බෙදාගෙන තිබේ නම් (ගතික) ඔහු ප්‍රතිදානය තුළ කේතය (සංකේත) ඇතුළත් නොකරයි, නමුත් ධාවන කාල බිඳ වැටීම් සිදුවිය හැක සිදු වේ

මේ ආකාරයේ දෝෂයක් විසඳන්නේ කෙසේද?

සම්පාදක කාල දෝෂය:

  • ඔබේ c ++ ව්‍යාපෘතිය සින්ටැක්ටිකල් නිවැරදිව ලිවීමට වග බලා ගන්න.

සම්බන්ධක කාල දෝෂය

  • ඔබගේ ශීර්ෂ ලිපිගොනු වල ඔබ ප්‍රකාශ කරන සියලුම සංකේත නිර්වචනය කරන්න
  • #pragma onceසම්පාදනය කර ඇති වත්මන් .cpp හි දැනටමත් එක් ශීර්ෂයක් ඇතුළත් කර ඇත්නම් සම්පාදකයාට ඉඩ නොදීමට භාවිතා කරන්න
  • ඔබගේ ශීර්ෂ ලිපිගොනු වල ඔබ අර්ථ දක්වා ඇති වෙනත් සංකේත සමඟ ගැටෙන සංකේත ඔබගේ බාහිර පුස්තකාලයේ නොමැති බවට වග බලා ගන්න
  • ඕනෑම අවස්ථාවකට සුදුසු කේතයක් සම්පාදනය කිරීමට සම්පාදකයාට ඉඩ දීම සඳහා ශීර්ෂ ගොනුවේ එක් එක් අච්චු ශ්‍රිතයේ අර්ථ දැක්වීම ඇතුළත් කිරීමට වග බලා ගැනීමට ඔබ අච්චුව භාවිතා කරන විට.

ඔබේ පිළිතුර දෘශ්‍ය චිත්‍රාගාරය සඳහා විශේෂිත නොවේද? ප්‍රශ්නය කිසිදු IDE / සම්පාදක මෙවලම් නියම නොකරන බැවින් දෘශ්‍ය-චිත්‍රාගාර නොවන කොටස් සඳහා ඔබේ පිළිතුර නිෂ් less ල වේ.
වික්ටර් පොලෙවෝයි

ඔයා හරි . නමුත් සෑම IDE ක්‍රියාවලියක්ම සම්පාදනය / සම්බන්ධ කිරීම තරමක් වෙනස් ආකාරයකින් සිදු කෙරෙමින් පවතී. නමුත් ලිපිගොනු හරියටම සකසනු ලැබේ (ධජ විග්‍රහ කිරීමේදී g ++ පවා එයම කරයි ..)

ගැටළුව ඇත්ත වශයෙන්ම IDE ගැන නොව ගැටලු සම්බන්ධ කිරීම සඳහා පිළිතුරකි. සම්බන්ධ කිරීමේ ගැටළු IDE හා සම්බන්ධ නොව සම්පාදක හා ගොඩනැගීමේ ක්‍රියාවලියට සම්බන්ධ වේ.
වික්ටර් පොලෙවෝයි

ඔව්. නමුත් ගොඩනැගීමේ / සම්බන්ධ කිරීමේ ක්‍රියාවලිය g ++ / Visual Studio (VS සඳහා මයික්‍රොසොෆ්ට් විසින් සපයන ලද සම්පාදකයා) / සූර්යග්‍රහණය / නෙට් බෝංචි යන ආකාරයෙන්ම සිදු කරයි

29

සම්පාදක / IDE හි දෝෂයකි

මට මෑතකදී මෙම ගැටලුව ඇති වූ අතර එය දෘශ්‍ය ස්ටුඩියෝ එක්ස්ප්‍රස් 2013 හි දෝෂයක් බව පෙනී ගියේය . ව්‍යාපෘතියෙන් ප්‍රභව ගොනුවක් ඉවත් කර දෝෂය මඟහරවා ගැනීම සඳහා එය නැවත එක් කිරීමට මට සිදු විය.

එය සම්පාදක / IDE හි දෝෂයක් විය හැකි යැයි ඔබ විශ්වාස කරන්නේ නම් උත්සාහ කිරීමට පියවර:

  • ව්‍යාපෘතිය පිරිසිදු කරන්න (සමහර IDE වලට මෙය කිරීමට විකල්පයක් ඇත, ඔබට වස්තු ලිපිගොනු මකාදැමීමෙන් එය අතින් කළ හැකිය)
  • සියලු ප්‍රභව කේත මුල් පිටපතෙන් පිටපත් කරමින් නව ව්‍යාපෘතියක් ආරම්භ කිරීමට උත්සාහ කරන්න.

5
ඔබේ මෙවලම් කැඩී ඇති බව විශ්වාස කිරීම බොහෝ දුරට ඔබව සැබෑ හේතුවෙන් er ත් කිරීමට හේතු වේ. සම්පාදකයෙකු ඔබේ ගැටලුවට හේතු වූවාට වඩා ඔබ වැරැද්දක් කිරීමට බොහෝ දුරට ඉඩ තිබේ. ඔබේ විසඳුම පිරිසිදු කිරීම හෝ ඔබේ ගොඩනැගීමේ වින්‍යාසය නැවත නිර්මාණය කිරීම මඟින් ගොඩනැගීමේ දෝෂ නිවැරදි කළ හැකි නමුත් එයින් අදහස් කරන්නේ සම්පාදකයාගේ දෝෂයක් නොමැති බවයි. සම්බන්ධිත "එය දෝෂයක් බවට පත් විය" මයික්‍රොසොෆ්ට් විසින් සනාථ කර නොමැති අතර එය ප්‍රජනනය කළ නොහැක.
JDiMatteo

4
@JDiMatteo මෙම ප්‍රශ්නයට පිළිතුරු 21 ක් ඇති අතර එබැවින් සැලකිය යුතු පිළිතුරු ප්‍රමාණයක් “විය හැකි” විසඳුමක් නොවනු ඇත. ඔබගේ සමානතා සීමාවට පහළින් ඇති සියලුම පිළිතුරු ඔබ බැහැර කරන්නේ නම්, මෙම පිටුව effectively ලදායී ලෙස නිෂ් less ල වනු ඇත, මන්ද බොහෝ පොදු අවස්ථා කෙසේ හෝ පහසුවෙන් හඳුනාගත හැකිය.
developerbmw

27

දෝෂය හඳුනා ගැනීමට ලින්කර් භාවිතා කරන්න

බොහෝ නූතන සම්බන්ධකයන්ට විවිධ මට්ටම් වලට මුද්‍රණය වන වාචික විකල්පයක් ඇතුළත් ය;

  • සම්බන්ධක ආයාචනය (විධාන රේඛාව),
  • සම්බන්ධක අදියරේදී ඇතුළත් කර ඇති පුස්තකාල පිළිබඳ දත්ත,
  • පුස්තකාලවල පිහිටීම,
  • භාවිතා කළ සෙවුම් මාර්ග.

Gcc සහ clang සඳහා; ඔබ සාමාන්යයෙන් එකතු කරන -v -Wl,--verboseහෝ -v -Wl,-vවිධාන රේඛාවේ කිරීමට. වැඩි විස්තර මෙහි සොයාගත හැකිය;

MSVC සඳහා, /VERBOSE(විශේෂයෙන් /VERBOSE:LIB) සම්බන්ධක විධාන රේඛාවට එකතු කරනු ලැබේ.


26

සම්බන්ධිත .lib ගොනුව .dll සමඟ සම්බන්ධ වේ

මටත් ඒ ප්‍රශ්නයම තිබුණා. මට MyProject සහ TestProject ව්‍යාපෘති ඇති බව පවසන්න. මම MyProject සඳහා වන lib ගොනුව TestProject සමඟ effectively ලදායී ලෙස සම්බන්ධ කර ඇත්තෙමි. කෙසේ වෙතත්, MyProject සඳහා DLL ගොඩනගා ඇති බැවින් මෙම lib ගොනුව නිපදවන ලදී. එසේම, MyProject හි සියලුම ක්‍රම සඳහා ප්‍රභව කේත මා සතුව නොතිබුණි, නමුත් DLL හි පිවිසුම් ස්ථාන වෙත ප්‍රවේශ වීම පමණි.

ගැටළුව විසඳීම සඳහා, මම MyProject එක LIB ලෙස ගොඩනඟා, TestProject මෙම .lib ගොනුවට සම්බන්ධ කළෙමි (මම උත්පාදනය කළ .lib ගොනුව TestProject ෆෝල්ඩරයට පිටපත් කරමි). මට නැවත ඩීඑල්එල් ලෙස MyProject ගොඩනගා ගත හැකිය. ටෙස්ට් ප්‍රොජෙක්ට් සම්බන්ධ කර ඇති ලිබයට මයිප්‍රොජෙක්ට් හි පන්තිවල සියලුම ක්‍රම සඳහා කේත අඩංගු බැවින් එය සම්පාදනය වේ.


25

සම්බන්ධක දෝෂ සම්බන්ධයෙන් මිනිසුන් මෙම ප්‍රශ්නයට යොමු වී ඇති බවක් පෙනෙන්නට ඇති හෙයින් මම මෙය මෙහි එක් කිරීමට යන්නෙමි.

GCC 5.2.0 සමඟ සම්බන්ධක දෝෂ ඇතිවිය හැකි එක් හේතුවක් නම් නව libstdc ++ පුස්තකාල ABI දැන් පෙරනිමියෙන් තෝරා ගැනීමයි.

Std :: __ cxx11 නාම අවකාශය හෝ [abi: cxx11] ටැගය ඇතුළත් වන සංකේත සඳහා නිර්වචනය නොකළ යොමු කිරීම් පිළිබඳ සම්බන්ධක දෝෂ ඔබට ලැබුනේ නම්, එවිට බොහෝ විට ඇඟවෙන්නේ _GLIBCXX_USE_CXX11_ABI සඳහා විවිධ අගයන් සමඟ සම්පාදනය කරන ලද වස්තු ගොනු එකට සම්බන්ධ කිරීමට ඔබ උත්සාහ කරන බවයි. සාර්ව. මෙය සාමාන්‍යයෙන් සිදුවන්නේ GCC හි පැරණි අනුවාදයක් සමඟ සම්පාදනය කරන ලද තෙවන පාර්ශවීය පුස්තකාලයකට සම්බන්ධ වන විට ය. තෙවන පාර්ශවීය පුස්තකාලය නව ABI සමඟ නැවත ගොඩනඟා ගත නොහැකි නම්, ඔබේ කේතය පැරණි ABI සමඟ නැවත සකස් කිරීමට ඔබට අවශ්‍ය වනු ඇත.

5.1.0 න් පසු GCC වෙත මාරුවීමේදී ඔබට හදිසියේම සම්බන්ධක දෝෂ ඇති වුවහොත් මෙය පරීක්ෂා කර බැලිය යුතු කරුණකි.


21

ඔබේ සම්බන්ධතාවය පුස්තකාල වෙත යොමු වන වස්තු ලිපිගොනු වලට පෙර ඒවා පරිභෝජනය කරයි

  • ඔබ උත්සාහ කරන්නේ ඔබේ වැඩසටහන GCC මෙවලම් කට්ටලය සමඟ සම්පාදනය කිරීමට හා සම්බන්ධ කිරීමට ය.
  • ඔබගේ සම්බන්ධතාවය මඟින් අවශ්‍ය සියලුම පුස්තකාල සහ පුස්තකාල සෙවුම් මාර්ග නියම කරයි
  • නම් libfooමත රඳා පවතී libbarනම් ඔබගේ සම්බන්ධතාවය නිවැරදිව තබන, libfooපෙර libbar.
  • ඔබගේ සම්බන්ධතාවය undefined reference to යම් දෝෂයකින් අසමත් වේ .
  • නමුත් සියලු නිර්වචනය නොකළ දෙයක් ඔබ සතුව ඇති ශීර්ෂ ලිපිගොනු වල ප්‍රකාශයට පත් කර ඇති #includeඅතර ඇත්ත වශයෙන්ම ඔබ සම්බන්ධ කරන පුස්තකාලවල අර්ථ දක්වා ඇත.

උදාහරණ සී හි ඇත. ඒවා සමානවම සී ++ විය හැකිය

ඔබ විසින්ම සාදන ලද ස්ථිතික පුස්තකාලයක් සම්බන්ධ අවම උදාහරණයක්

my_lib.c

#include "my_lib.h"
#include <stdio.h>

void hw(void)
{
    puts("Hello World");
}

my_lib.h

#ifndef MY_LIB_H
#define MT_LIB_H

extern void hw(void);

#endif

eg1.c

#include <my_lib.h>

int main()
{
    hw();
    return 0;
}

ඔබ ඔබේ ස්ථිතික පුස්තකාලය සාදයි:

$ gcc -c -o my_lib.o my_lib.c
$ ar rcs libmy_lib.a my_lib.o

ඔබ ඔබේ වැඩසටහන සම්පාදනය කරයි:

$ gcc -I. -c -o eg1.o eg1.c

ඔබ එය සමඟ සම්බන්ධ වීමට උත්සාහ කර libmy_lib.aඅසමත් වේ:

$ gcc -o eg1 -L. -lmy_lib eg1.o 
eg1.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

ඔබ එක් පියවරක් සම්පාදනය කර සම්බන්ධ කරන්නේ නම් එකම ප්‍රති result ලය, වැනි:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c
/tmp/ccQk1tvs.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

හවුල් පද්ධති පුස්තකාලයක්, සම්පීඩන පුස්තකාලය සම්බන්ධ අවම උදාහරණයක් libz

eg2.c

#include <zlib.h>
#include <stdio.h>

int main()
{
    printf("%s\n",zlibVersion());
    return 0;
}

ඔබේ වැඩසටහන සම්පාදනය කරන්න:

$ gcc -c -o eg2.o eg2.c

ඔබේ වැඩසටහන සමඟ සම්බන්ධ වීමට උත්සාහ කර libzඅසමත් වන්න:

$ gcc -o eg2 -lz eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

ඔබ එකවර සම්පාදනය කර සම්බන්ධ කරන්නේ නම් එයම වේ:

$ gcc -o eg2 -I. -lz eg2.c
/tmp/ccxCiGn7.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

උදාහරණ 2 හි විචලනය pkg-config:

$ gcc -o eg2 $(pkg-config --libs zlib) eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'

ඔබ කරන්නේ කුමක්ද?

ඔබේ වැඩසටහන සෑදීම සඳහා ඔබට සම්බන්ධ කිරීමට අවශ්‍ය වස්තු ලිපිගොනු සහ පුස්තකාල අනුක්‍රමය තුළ, ඔබ පුස්තකාල ඒවා යොමු කරන වස්තු ලිපිගොනු ඉදිරියේ තබයි. පුස්තකාල ඒවා යොමු කරන වස්තු ලිපිගොනු පසු ඒවා තැබිය යුතුය.

උදාහරණ 1 නිවැරදිව සම්බන්ධ කරන්න:

$ gcc -o eg1 eg1.o -L. -lmy_lib

සාර්ථකත්වය:

$ ./eg1 
Hello World

උදාහරණ 2 නිවැරදිව සම්බන්ධ කරන්න:

$ gcc -o eg2 eg2.o -lz

සාර්ථකත්වය:

$ ./eg2 
1.2.8

උදාහරණ 2 pkg-configවිචලනය නිවැරදිව සම්බන්ධ කරන්න:

$ gcc -o eg2 eg2.o $(pkg-config --libs zlib) 
$ ./eg2
1.2.8

පැහැදිලි කිරීම

මෙතැන් සිට කියවීම අත්‍යවශ්‍ය නොවේ .

පෙරනිමියෙන්, ඔබේ ඩිස්ට්‍රෝ හි GCC විසින් ජනනය කරන ලද සම්බන්ධක විධානයක්, සම්බන්ධකයේ ඇති ලිපිගොනු වමේ සිට දකුණට විධාන රේඛා අනුපිළිවෙලින් පරිභෝජනය කරයි. ගොනුවක් යනු යම් දෙයකට යොමු වන බව සොයාගත් විට සඳහා අර්ථ දැක්වීමක් නොමැති , තව දුරටත් දකුණට ඇති ලිපිගොනු වල අර්ථ දැක්වීමක් සෙවීම. එය අවසානයේ අර්ථ දැක්වීමක් සොයා ගන්නේ නම්, යොමු කිරීම විසඳනු ලැබේ. කිසියම් යොමු කිරීමක් අවසානයේ නොවිසඳී පවතින්නේ නම්, සම්බන්ධතාවය අසමත් වේ: සම්බන්ධකය පසුපසට සොයන්නේ නැත.

පළමුව, උදාහරණ 1 , ස්ථිතික පුස්තකාලය සමඟmy_lib.a

ස්ථිතික පුස්තකාලයක් යනු වස්තු ලිපිගොනු සුචිගත කරන ලද ලේඛනාගාරයකි. -lmy_libසම්බන්ධක අනුක්‍රමය තුළ සම්බන්ධකය සොයාගත් විට මෙය ස්ථිතික පුස්තකාලයට යොමු වන බව දැනගත් විට ./libmy_lib.a, එය ඔබගේ වැඩසටහනට කිසියම් වස්තු ලිපිගොනු අවශ්‍ය දැයි දැන ගැනීමට අවශ්‍ය වේ libmy_lib.a.

එහි ඇත්තේ වස්තු ගොනුවක් පමණි libmy_lib.a, එනම් my_lib.oඅර්ථ දැක්වෙන්නේ එක් දෙයක් පමණි my_lib.o, එනම් ශ්‍රිතයයිhw .

ඔබේ වැඩසටහනට my_lib.oඑය දැනටමත් වැඩසටහනට hwඑකතු කර ඇති වස්තු ලිපිගොනු එකක් හෝ වැඩි ගණනක් ගැන සඳහන් කර ඇති බවත් , එය දැනටමත් එකතු කර ඇති වස්තු ලිපිගොනු කිසිවක් අඩංගු නොවන බවත් ඔබේ වැඩසටහනට අවශ්‍ය බව සම්බන්ධකය තීරණය කරයි . සඳහා අර්ථ දැක්වීම hw.

එය සත්‍ය නම්, සම්බන්ධකය my_lib.oපුස්තකාලයෙන් පිටපතක් ලබා ගෙන එය ඔබේ වැඩසටහනට එක් කරයි. එවිට, ඔබේ වැඩසටහන සඳහා අර්ථ දැක්වීමක් අඩංගු වේ hw, එබැවින් එහි යොමු hwකිරීම් නිරාකරණය වේ.

ඔබ වැඩසටහන සම්බන්ධ කිරීමට උත්සාහ කරන විට:

$ gcc -o eg1 -L. -lmy_lib eg1.o

එය දකින විට සම්බන්ධකය වැඩසටහනට එකතු කර නැත . මන්දයත් එම අවස්ථාවේදී එය දැක නැති බැවිනි . ඔබගේ වැඩසටහන තවමත් කිසිදු යොමු කරන්නේ නැහැ : එය තවම යොමු කරන්නේ නැහැ සියලු දී සියලු යොමු එය වර්ගයන් ඇති නිසා, .eg1.o -lmy_libeg1.ohweg1.o

එබැවින් සම්බන්ධකය my_lib.oවැඩසටහනට එකතු නොකරන අතර වැඩිදුර භාවිතයක් නොමැත libmy_lib.a.

ඊළඟට, එය සොයා ගන්නා eg1.oඅතර එය වැඩසටහනක් ලෙස එකතු කරයි. සම්බන්ධක අනුපිළිවෙලෙහි වස්තු ගොනුවක් සෑම විටම වැඩසටහනට එකතු වේ. දැන්, වැඩසටහන යොමු කිරීමක් කරයි hw, සහ එහි අර්ථ දැක්වීමක් අඩංගු නොවේ hw; නමුත් සම්බන්ධක අනුක්‍රමය තුළ අස්ථානගත වූ අර්ථ දැක්වීමක් සැපයිය හැකි කිසිවක් නොමැත. යොමු කිරීම නොවිසඳීhw අවසන් වන අතර සම්බන්ධතාවය අසමත් වේ.

දෙවනුව, උදාහරණ 2 , හවුල් පුස්තකාලය සමඟlibz

හවුල් පුස්තකාලයක් යනු වස්තු ලිපිගොනු හෝ ඒ හා සමාන කිසිවක් නොවේ. එය බොහෝ විට ශ්‍රිතයක් නොමැති වැඩසටහනකට සමාන වන අතර mainඒ වෙනුවට එය අර්ථ දක්වන වෙනත් සංකේත කිහිපයක් නිරාවරණය කරයි, එවිට වෙනත් වැඩසටහන් වලට ඒවා ක්‍රියාත්මක වේලාවේදී භාවිතා කළ හැකිය.

බොහෝ ලිනක්ස් distros අද ඔවුන්ගේ ගල්ෆ් toolchain එහි භාෂාව රියදුරන් (එබැවින් මාන gcc, g++, gfortranආදිය) මෙම පද්ධතිය linker උපදෙස් ලබා ( ld) සම්බන්ධ කිරීමට මත පුස්තකාල හවුල් වැනි අවශ්ය පදනම. ඔබට එම ඩිස්ට්‍රෝ වලින් එකක් තිබේ.

මෙයින් අදහස් කරන්නේ -lzසම්බන්ධක අනුක්‍රමය තුළ සම්බන්ධකය සොයාගත් විට සහ මෙය හවුල් පුස්තකාලයට (කියන්න) /usr/lib/x86_64-linux-gnu/libz.soයොමු වූ විට, එය ඔබගේ වැඩසටහනට එකතු කර ඇති කිසියම් සඳහනක් තවමත් අර්ථ දක්වා නොමැතිද යන්න දැන ගැනීමට අවශ්‍ය බව ය. විසින් අපනයනය කරන ලදිlibz

බව සැබෑ නම්, ඊට linker ඇත නොහැකි අතරින් කුමන හෝ කුට්ටි පිටපත් libzසහ ඔබේ වැඩසටහන එකතු; ඒ වෙනුවට, එය ඔබගේ වැඩසටහනේ කේතය වෛද්‍යවරයා විසින් පමණක් කරනු ඇත: -

  • ධාවන වේලාවේදී, පද්ධති ක්‍රමලේඛ පැටවුම libzඔබගේ වැඩසටහනේ පිටපතක් පටවන සෑම අවස්ථාවකම එය ක්‍රියාත්මක කිරීම සඳහා ඔබේ වැඩසටහනේ පිටපතක් පටවනු ඇත.

  • ධාවන වේලාවේදී, ඔබේ වැඩසටහන අර්ථ දක්වා ඇති දෙයක් ගැන සඳහන් කරන සෑම විටම libz, එම යොමු libzකිරීම එකම ක්‍රියාවලියේ පිටපත මඟින් අපනයනය කළ අර්ථ දැක්වීම භාවිතා කරයි .

ඔබගේ වැඩසටහනට නිර්වචනය කර ඇති එක් දෙයක් පමණක් යොමු කිරීමට අවශ්‍යය libz, එනම් ශ්‍රිතය zlibVersion, එක් වරක් පමණක් සඳහන් වේ eg2.c. සම්බන්ධකය ඔබේ වැඩසටහනට එම සඳහන එකතු කර අපනයනය කළ අර්ථ දැක්වීම සොයා ගන්නේ නම් libz, යොමු කිරීම විසඳනු ලැබේ

නමුත් ඔබ වැඩසටහන සම්බන්ධ කිරීමට උත්සාහ කරන විට:

gcc -o eg2 -lz eg2.o

සිදුවීම් අනුපිළිවෙල උදාහරණයක් 1. මෙන් හුදෙක් එකම විදිහට වැරදි විට linker සොයාගැනීම් මෙම අවස්ථාවේදී -lz, පවතින කිසිම වැඩසටහන තුල කිසිවක් යොමු: ඔවුන් සියලු eg2.oතවමත් දැක නැති අතර,. එබැවින් සම්බන්ධකය තීරණය කරන්නේ එයින් කිසිදු ප්‍රයෝජනයක් නොමැති libzබවයි. එය ළඟා වූ විට eg2.o, එය වැඩසටහනට එක් කරයි, පසුව නිශ්චිතව දක්වා නැතzlibVersion , සම්බන්ධක අනුක්‍රමය අවසන් වේ; එම සඳහන නොවිසඳී ඇති අතර සම්බන්ධතාවය අසමත් වේ.

අවසාන වශයෙන්, pkg-configඋදාහරණ 2 හි විචල්‍යතාවයට දැන් පැහැදිලි පැහැදිලි කිරීමක් ඇත. කවච පුළුල් කිරීමෙන් පසු:

gcc -o eg2 $(pkg-config --libs zlib) eg2.o

බවට පත්වේ:

gcc -o eg2 -lz eg2.o

එය නැවතත් උදාහරණ 2 යි.

උදාහරණ 1 හි මට ගැටලුව ප්‍රතිනිෂ්පාදනය කළ හැකිය, නමුත් උදාහරණ 2 හි නොවේ

සම්බන්ධතාවය:

gcc -o eg2 -lz eg2.o

ඔබට හොඳින් වැඩ කරයි!

(හෝ: එම සම්බන්ධතාවය ඔබට ෆෙඩෝරා 23 හි හොඳට වැඩ කළ නමුත් උබුන්ටු 16.04 හි අසමත් වේ)

එයට හේතුව, සම්බන්ධතාවය ක්‍රියාත්මක වන ඩිස්ට්‍රෝ එක එහි GCC මෙවලම් කට්ටලය අවශ්‍ය පරිදි හවුල් පුස්තකාල සම්බන්ධ කිරීම සඳහා වින්‍යාස නොකරන එකකි . .

යුනික්ස් වැනි පද්ධති ස්ථිතික හා බෙදාගත් පුස්තකාල විවිධ නීති රීති වලට සම්බන්ධ කිරීම සාමාන්‍ය දෙයක් විය. උදාහරණ 1 හි විස්තර කර ඇති පරිදි සම්බන්ධක අනුපිළිවෙලක ස්ථිතික පුස්තකාල අවශ්‍ය පරිදි සම්බන්ධ කර ඇත , නමුත් හවුල් පුස්තකාල කොන්දේසි විරහිතව සම්බන්ධ කර ඇත.

මෙම හැසිරීම සම්බන්ධක වේලාවේදී ලාභදායී වන්නේ වැඩසටහනට හවුල් පුස්තකාලයක් අවශ්‍ය දැයි සම්බන්ධකයට සිතා බැලිය යුතු නැති බැවිනි: එය හවුල් පුස්තකාලයක් නම් එය සම්බන්ධ කරන්න. බොහෝ සම්බන්ධතා වල ඇති පුස්තකාල බොහෝමයක් හවුල් පුස්තකාල වේ. නමුත් අවාසි ද ඇත: -

  • එය අපහරණය වේ ධාවන එය ඔවුන්ට අවශ්ය වන්නේ නැත පවා නම් පුස්තකයන් වැඩසටහනක් සමග පැටවිය කිරීමට හේතු නිසා.

  • ස්ථිතික හා පුස්තකයන් සඳහා විවිධ සම්බන්ධතාවය නිසාම නීති නොදැන සිටි යන්න inexpert වැඩසටහන්කරුවන්, දීමට අපහසුය -lfooඔවුන්ගේ සම්බන්ධය පරීක්ෂා හි අධිෂ්ඨානය යන්නේ /some/where/libfoo.aහෝ /some/where/libfoo.so, කෙසේ හෝ හවුල් හා ස්ථිතික පුස්තකාල අතර ඇති වෙනස තේරුම් නොහැකි විය.

මෙම වෙළඳාම අද වන විට භේදකාරී තත්වයට හේතු වී තිබේ. සමහර පුස්තකාලයන් හවුල් පුස්තකාල සඳහා ඔවුන්ගේ ජීසීසී සම්බන්ධතා නීති වෙනස් කර ඇති අතර එමඟින් අවශ්‍ය පුස්තකාලය සියලුම පුස්තකාල සඳහා අදාළ වේ. සමහර ඩිස්ට්‍රෝ පැරණි ක්‍රමයට ඇලී තිබේ.

මම එකවර සම්පාදනය කර සම්බන්ධ කළද මට තවමත් මෙම ගැටලුව ඇතිවන්නේ ඇයි?

මම එසේ කරන්නේ නම්:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c

නියත වශයෙන්ම gcc විසින් සම්පාදනය කළ යුතු අතර eg1.c, පසුව ලැබෙන වස්තු ගොනුව සමඟ සම්බන්ධ කරන්නlibmy_lib.a . එසේ නම්, එය සම්බන්ධ කිරීමේදී වස්තු ගොනුව අවශ්‍ය බව දැන නොගන්නේ කෙසේද?

තනි විධානයක් සමඟ සම්පාදනය කිරීම හා සම්බන්ධ කිරීම සම්බන්ධක අනුක්‍රමයේ අනුපිළිවෙල වෙනස් නොකරන බැවිනි.

ඔබ ඉහත විධානය ක්‍රියාත්මක කරන විට, ඔබට gccසම්පාදනය + සම්බන්ධතාවය අවශ්‍ය බව හදුනා ගනී. තිරය ​​පිටුපස, එය සම්පාදන විධානයක් ජනනය කර එය ක්‍රියාත්මක කරයි, පසුව සම්බන්ධක විධානයක් ජනනය කරයි, එය ක්‍රියාත්මක කරන්නේ ඔබ විධාන දෙක ක්‍රියාත්මක කළ ආකාරයට ය:

$ gcc -I. -c -o eg1.o eg1.c
$ gcc -o eg1 -L. -lmy_lib eg1.o

ඒ නිසා සම්බන්ධය පරීක්ෂා නම් ඔබ එය කරන්නේ මෙන් අසමත් නැහැ එම විධාන දෙකක් ධාවනය. අසමත් වීමේදී ඔබ දකින එකම වෙනස වන්නේ සම්පාදනය + සම්බන්ධක නඩුවේදී gcc විසින් තාවකාලික වස්තු ගොනුවක් ජනනය කර eg1.oතිබීමයි , මන්ද ඔබ එය භාවිතා කිරීමට නොකියන බැවිනි . අපට පෙනේ:

/tmp/ccQk1tvs.o: In function `main'

වෙනුවට:

eg1.o: In function `main':

මෙයද බලන්න

එකිනෙකට පරායත්ත සම්බන්ධිත පුස්තකාල නියම කර ඇති අනුපිළිවෙල වැරදිය

එකිනෙකට පරායත්ත පුස්තකාල වැරදි අනුපිළිවෙලට තැබීම ඔබට අර්ථ දැක්වීම් සපයන ලිපිගොනු වලට වඩා සම්බන්ධතාවයේ පසුව එන දේවල් පිළිබඳ අර්ථ දැක්වීම් අවශ්‍ය ගොනු ලබා ගත හැකි එක් ක්‍රමයකි . පුස්තකාල ඒවා යොමු කරන වස්තු ලිපිගොනු ඉදිරියේ තැබීම එකම වැරැද්ද කිරීමේ තවත් ක්‍රමයකි.


20

සම්බන්ධක ස්ක්‍රිප්ට් සඳහා සහය නොදක්වන GNU ld වටා එතීම

සමහර .so ගොනු ඇත්ත වශයෙන්ම GNU ld සම්බන්ධක ස්ක්‍රිප්ට් වේ , උදා: libtbb.so ගොනුව මෙම අන්තර්ගතයන් සහිත ASCII පෙළ ගොනුවකි:

INPUT (libtbb.so.2)

තවත් සමහර සංකීර්ණ ගොඩනැඟිලි මෙයට සහාය නොදක්වයි. උදාහරණයක් ලෙස, ඔබ සම්පාදක විකල්පයන්හි -v ඇතුළත් කළහොත්, සම්බන්ධ වීමට ඇති පුස්තකාලවල වාචික ප්‍රතිදාන ලැයිස්තුවේ ප්‍රධාන ලින්ක් ස්ක්‍රිප්ට් විධාන ලිපිගොනු ඉවතලන බව ඔබට පෙනේ . සම්බන්ධක ස්ක්‍රිප්ට් ආදාන විධානය ප්‍රතිස්ථාපනය කිරීම සරල වැඩකි. ගොනුවේ පිටපතක් සහිත ගොනුවක් (හෝ සිම්ලින්ක්), උදා

cp libtbb.so.2 libtbb.so

හෝ ඔබ වෙනුවට උදාහරණ, .ඒ සම්පූර්ණ මාර්ගය සමඟ -L තර්කය වෙනුවට හැකි -ltbbකරන්නද/home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2


18

සැකිලි සමඟ මිතුරු ...

මිතුරු ක්‍රියාකරුවෙකු (හෝ ශ්‍රිතය) සමඟ අච්චු වර්ගයක කේත ස්නිපටය ලබා දී ඇත;

template <typename T>
class Foo {
    friend std::ostream& operator<< (std::ostream& os, const Foo<T>& a);
};

මෙම operator<<A-සැකිල්ල නොවන ශ්රිතයක් ලෙස ප්රකාශයට පත් කොට ඇත. Tභාවිතා කරන සෑම වර්ගයක් සඳහාම Foo, සැකිලි රහිත විය යුතුය operator<<. උදාහරණයක් ලෙස, Foo<int>ප්‍රකාශිත වර්ගයක් තිබේ නම් , පහත පරිදි ක්‍රියාකරු ක්‍රියාත්මක කිරීමක් තිබිය යුතුය;

std::ostream& operator<< (std::ostream& os, const Foo<int>& a) {/*...*/}

එය ක්‍රියාත්මක නොවන බැවින්, සම්බන්ධකය එය සොයා ගැනීමට අපොහොසත් වන අතර එහි ප්‍රති results ලය දෝෂයකි.

මෙය නිවැරදි කිරීම සඳහා, ඔබට Fooටයිප් කිරීමට පෙර අච්චු ක්‍රියාකරුවෙකු ප්‍රකාශයට පත් කළ හැකි අතර පසුව සුදුසු මිතුරෙකු ලෙස ප්‍රකාශ කළ හැකිය. වාක්‍ය ඛණ්ඩය ටිකක් අමුතුයි, නමුත් පහත පරිදි පෙනේ;

// forward declare the Foo
template <typename>
class Foo;

// forward declare the operator <<
template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&);

template <typename T>
class Foo {
    friend std::ostream& operator<< <>(std::ostream& os, const Foo<T>& a);
    // note the required <>        ^^^^
    // ...
};

template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&)
{
  // ... implement the operator
}

ඉහත කේතය මඟින් ක්‍රියාකරුගේ මිත්‍රත්වය අනුරූපී ක්ෂණිකකරණයට සීමා කරයි Foo, එනම් operator<< <int>ක්ෂණිකකරණය ක්ෂණිකකරණයේ පෞද්ගලික සාමාජිකයින්ට ප්‍රවේශ වීම සඳහා සීමා වේ Foo<int>.

විකල්ප ඇතුළත්;

  • පහත දැක්වෙන පරිදි, සැකිලි වල සියලු අවස්ථා දක්වා මිත්‍රත්වයට ඉඩ දීම;

    template <typename T>
    class Foo {
        template <typename T1>
        friend std::ostream& operator<<(std::ostream& os, const Foo<T1>& a);
        // ...
    };
  • නැතහොත්, operator<<පන්ති අර්ථ දැක්වීම තුළ ඇතුළත ක්‍රියාත්මක කළ හැකිය;

    template <typename T>
    class Foo {
        friend std::ostream& operator<<(std::ostream& os, const Foo& a)
        { /*...*/ }
        // ...
    };

සටහන , ක්රියාකරු (හෝ කාර්යය) ප්රකාශයට පත් පමණක් පන්තියේ ප්රකාශ වන විට, එම නම, "සාමාන්ය" විමසුම්, තර්කය රඳා බැලීම සඳහා පමණක් ලබා ගත හැකි නොවේ cppreference ;

පංතියේ හෝ පන්තියේ අච්චුව තුළ මිතුරු ප්‍රකාශයක මුලින් ප්‍රකාශයට පත් කරන ලද නමක් X හි අභ්‍යන්තරයේ ඇති නාම අවකාශයේ සාමාජිකයෙකු බවට පත්වේ, නමුත් නාම අවකාශයේ විෂය පථයට ගැලපෙන ප්‍රකාශයක් මිස, බැලීමට (X ලෙස සලකන තර්ක-රඳා පවතින විමසුම හැර) බැලීමට ප්‍රවේශ විය නොහැක. සපයා ඇත ...

Cppreference සහ C ++ නිති අසන ප්‍රශ්න වලදී අච්චු මිතුරන් පිළිබඳ වැඩිදුර කියවීමක් ඇත .

ඉහත ක්‍රමෝපායන් පෙන්වන කේත ලැයිස්තුගත කිරීම .


අසමත් වූ කේත සාම්පලයට පැති සටහනක් ලෙස; g ++ පහත සඳහන් පරිදි මේ ගැන අනතුරු අඟවයි

warning: friend declaration 'std::ostream& operator<<(...)' declares a non-template function [-Wnon-template-friend]

note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)


16

ඔබගේ ඇතුළත් කිරීමේ මාර්ග වෙනස් වන විට

ශීර්ෂ ගොනුවක් සහ ඒ හා සම්බන්ධ හවුල් පුස්තකාලය (.lib ගොනුව) සමමුහුර්තකරණයෙන් ඉවත් වූ විට සම්බන්ධක දෝෂ සිදුවිය හැකිය. මට පැහැදිලි කරන්න දෙන්න.

සම්බන්ධකයන් ක්‍රියා කරන්නේ කෙසේද? සම්බන්ධකය ඔවුන්ගේ අත්සන් සංසන්දනය කිරීමෙන් ශ්‍රිත ප්‍රකාශනයකට (ශීර්ෂයේ ප්‍රකාශයට පත් කර ඇත) එහි අර්ථ දැක්වීම සමඟ (හවුල් පුස්තකාලයේ) ගැලපේ. සම්බන්ධකයට පරිපූර්ණව ගැලපෙන ශ්‍රිත අර්ථ දැක්වීමක් සොයාගත නොහැකි නම් ඔබට සම්බන්ධක දෝෂයක් ලබා ගත හැකිය.

ප්‍රකාශය සහ අර්ථ දැක්වීම ගැලපෙන බවක් පෙනෙන්නට තිබුණද තවමත් සම්බන්ධක දෝෂයක් ලබා ගත හැකිද? ඔව්! ප්‍රභව කේත වලදී ඒවා එක හා සමාන විය හැකි නමුත් එය සැබවින්ම රඳා පවතින්නේ සම්පාදකයා දකින දේ මත ය. අත්යවශ්යයෙන්ම ඔබට මෙවැනි තත්වයක් ඇතිවිය හැකිය:

// header1.h
typedef int Number;
void foo(Number);

// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically

ශ්‍රිත ප්‍රකාශන දෙකම ප්‍රභව කේතයට සමාන වුවත්, සම්පාදකයාට අනුව ඒවා සැබවින්ම වෙනස් වන්නේ කෙසේදැයි බලන්න.

එවැනි තත්වයක් තුළ යමෙකු අවසන් වන්නේ කෙසේදැයි ඔබට ඇසිය හැකිය. ඇත්ත වශයෙන්ම මාර්ග ඇතුළත් කරන්න ! හවුල් පුස්තකාලය සම්පාදනය කිරීමේදී, ඇතුළත් කිරීමේ මාවත මඟ පෙන්වන header1.hඅතර ඔබ header2.hඔබේම වැඩසටහනක භාවිතා කිරීම අවසන් කරන්නේ නම්, සිදුවූයේ කුමක්දැයි කල්පනා කරමින් ඔබේ ශීර්ෂකය සීරීමට ලක් වනු ඇත (pun අරමුණ).

සැබෑ ලෝකයේ මෙය සිදුවිය හැකි ආකාරය පිළිබඳ උදාහරණයක් පහත විස්තර කෙරේ.

උදාහරණයක් සමඟ තවදුරටත් විස්තර කිරීම

මට ව්‍යාපෘති දෙකක් තිබේ: graphics.libසහ main.exe. ව්‍යාපෘති දෙකම රඳා පවතී common_math.h. පුස්තකාලය පහත ශ්‍රිතය අපනයනය කරයි යැයි සිතමු:

// graphics.lib    
#include "common_math.h" 
   
void draw(vec3 p) { ... } // vec3 comes from common_math.h

ඉන්පසු ඔබ ඉදිරියට ගොස් පුස්තකාලය ඔබේම ව්‍යාපෘතියකට ඇතුළත් කරන්න.

// main.exe
#include "other/common_math.h"
#include "graphics.h"

int main() {
    draw(...);
}

උත්පාතය! ඔබට සම්බන්ධක දෝෂයක් ඇති අතර එය අසමත් වන්නේ මන්දැයි ඔබට අදහසක් නැත. හේතුව, පොදු පුස්තකාලය එකම ඇතුළත් විවිධ අනුවාදයන් භාවිතා කිරීමයි common_math.h(මම වෙනත් උදාහරණයකින් මෙහි උදාහරණයෙන් පැහැදිලි කර ඇත්තෙමි, නමුත් එය සැමවිටම එතරම් පැහැදිලිව පෙනෙන්නට නොතිබිය හැකිය. සමහර විට ඇතුළත් කිරීමේ මාර්ගය සම්පාදක සැකසුම් තුළ වෙනස් වේ) .

මෙම උදාහරණයේ සටහන් කරන්න, එය සොයාගත නොහැකි බව සම්බන්ධකය ඔබට කියනු draw()ඇත, යථාර්ථයේ දී ඔබ එය පැහැදිලිවම පුස්තකාලයෙන් අපනයනය කරන බව ඔබ දන්නා විට. වැරැද්ද කුමක්දැයි කල්පනා කරමින් ඔබේ හිස සීරීමට ඔබට පැය ගණනක් ගත කළ හැකිය. කාරණය වන්නේ, පරාමිති වර්ග තරමක් වෙනස් බැවින් සම්බන්ධකය වෙනස් අත්සනක් දකී. උදාහරණයේ දී, vec3සම්පාදකයා සැලකිලිමත් වන පරිදි ව්‍යාපෘති දෙකෙහිම වෙනස් වර්ගයකි. මෙය සිදුවිය හැක්කේ ඒවා තරමක් වෙනස් ගොනු දෙකකින් පැමිණීම නිසා විය හැකිය (සමහර විට ඇතුළත් කළ හැකි ලිපිගොනු පුස්තකාලයේ විවිධ අනුවාද දෙකකින් පැමිණේ).

සම්බන්ධකය නිදොස් කිරීම

ඔබ විෂුවල් ස්ටුඩියෝ භාවිතා කරන්නේ නම් ඩම්ප්බින් ඔබේ මිතුරා ය. මට විශ්වාසයි වෙනත් සම්පාදකයින්ට වෙනත් සමාන මෙවලම් ඇති බව.

ක්‍රියාවලිය මේ ආකාරයට ය:

  1. සම්බන්ධක දෝෂයේ දක්වා ඇති අමුතු මැංගල් නාමය සටහන් කරන්න. (උදා. අදින්න @ ග්‍රැෆික්ස් @ XYZ).
  2. පුස්තකාලයෙන් අපනයනය කළ සංකේත පෙළ ගොනුවකට දමන්න.
  3. අපනයනය කරන ලද පොලී සංකේතය සොයන්න, සහ අඹරන ලද නම වෙනස් බව සලකන්න.
  4. අඹරන ලද නම් වෙනස් වූයේ මන්ද යන්න පිළිබඳව අවධානය යොමු කරන්න. පරාමිති වර්ග ප්‍රභව කේතයේ එක හා සමාන වුවත් ඒවා වෙනස් බව ඔබට දැකගත හැකිය.
  5. ඒවා වෙනස් වීමට හේතුව. ඉහත දක්වා ඇති උදාහරණයේ දී, විවිධ ඇතුළත් ගොනු නිසා ඒවා වෙනස් වේ.

[1] ව්‍යාපෘතිය අනුව මා අදහස් කරන්නේ පුස්තකාලයක් හෝ ක්‍රියාත්මක කළ හැකි එකක් නිෂ්පාදනය කිරීම සඳහා එකට සම්බන්ධ කර ඇති ප්‍රභව ගොනු සමූහයකි.

සංස්කරණය 1: තේරුම් ගැනීමට පහසු වන පරිදි පළමු කොටස නැවත ලියන්න. වෙනත් දෙයක් නිවැරදි කිරීමට අවශ්‍ය දැයි මට දන්වන්න කරුණාකර පහත අදහස් දක්වන්න. ස්තූතියි!


15

නොගැලපෙන UNICODEනිර්වචන

වින්ඩෝස් යුනිකෝඩ් ගොඩ නැඟීමට සමග ඉදිකර ඇත TCHARලෙස අර්ථ ආදිය wchar_tසමග ගොඩ නොවන විට ආදිය UNICODEසමග ගොඩ නැඟීමට ලෙස අර්ථ TCHARලෙස අර්ථ charමෙම ආදිය UNICODEහා _UNICODEනිර්වචනය කරන සියලු බලපාන " T" string වර්ග ; LPTSTR, LPCTSTRසහ ඔවුන්ගේ එල්ක්.

එක් පුස්තකාලයක් UNICODEනිර්වචනය කර ඇති අතර UNICODEඑය නිර්වචනය කර නොමැති ව්‍යාපෘතියකට සම්බන්ධ කිරීමට උත්සාහ කිරීම සම්බන්ධක දෝෂ වලට හේතු වනු ඇත TCHAR. charඑදිරිව wchar_t.

දෝෂය සාමාන්‍යයෙන් ශ්‍රිතයක් charහෝ wchar_tව්‍යුත්පන්න වර්ගයක් සහිත අගයක් ඇතුළත් වේ , මේවාට ද ඇතුළත් විය std::basic_string<>හැකිය. කේතයේ බලපෑමට ලක් වූ ශ්‍රිතය හරහා සැරිසරන විට, බොහෝ විට යොමු දැක්වීමක් TCHARහෝ std::basic_string<TCHAR>යනාදිය සිදුවනු ඇත . මෙය කේතය මුලින් අදහස් කළේ යුනිකෝඩ් සහ බහු-බයිට් අක්‍ෂර (හෝ “පටු”) ගොඩනැගීම සඳහා ය. .

මෙය නිවැරදි කිරීම සඳහා, UNICODE(සහ _UNICODE) පිළිබඳ නිශ්චිත අර්ථ දැක්වීමකින් අවශ්‍ය සියලුම පුස්තකාල සහ ව්‍යාපෘති ගොඩනඟන්න .

  1. මෙය එක්කෝ කළ හැකිය;

    #define UNICODE
    #define _UNICODE
  2. හෝ ව්යාපෘති සැකසුම් තුළ;

    ව්‍යාපෘති ගුණාංග> සාමාන්‍ය> ව්‍යාපෘති පෙරනිමි> අක්‍ෂර කට්ටලය

  3. හෝ විධාන රේඛාවේ;

    /DUNICODE /D_UNICODE

විකල්පය ද අදාළ වේ, යුනිකෝඩ් භාවිතා කිරීමට අදහස් නොකරන්නේ නම්, නිර්වචන සකසා නොමැති බවට වග බලා ගන්න, සහ / හෝ බහු අක්ෂර සැකසුම ව්‍යාපෘතිවල භාවිතා වන අතර නිරන්තරයෙන් අදාළ වේ.

"මුදා හැරීම" සහ "නිදොස්කරණය" ගොඩනැගීම් අතර අනුකූල වීමට අමතක නොකරන්න.


14

පිරිසිදු කර නැවත ගොඩනඟන්න

ගොඩනැඟිල්ලේ “පිරිසිදු” කිරීමකට පෙර ගොඩනැඟිලි, අසාර්ථක ගොඩනැඟිලි, අසම්පූර්ණ ගොඩනැඟිලි සහ වෙනත් ගොඩනැඟිලි පද්ධතියට සම්බන්ධ ගොඩනැගිලි ගැටළු වලින් ඉතිරිව ඇති “මළ දැව” ඉවත් කළ හැකිය.

පොදුවේ ගත් කල, IDE හෝ ගොඩනැගීමට යම් ආකාරයක “පිරිසිදු” ශ්‍රිතයක් ඇතුළත් වේ, නමුත් මෙය නිවැරදිව වින්‍යාස කර නොතිබිය හැකිය (උදා: අතින් සාදන ලද ගොනුවක) හෝ අසමත් විය හැකිය (උදා: අතරමැදි හෝ ප්‍රති ant ල ද්විමය කියවීමට පමණි).

"පිරිසිදු" සම්පුර්ණ වූ පසු, "පිරිසිදු" සාර්ථක වී ඇති බවත්, ජනනය කරන ලද අතරමැදි ගොනුව (උදා: ස්වයංක්‍රීය මේක්ෆයිල්) සාර්ථකව ඉවත් කර ඇති බවත් තහවුරු කරන්න.

මෙම ක්‍රියාවලිය අවසාන නිකේතනයක් ලෙස දැකිය හැකි නමුත් බොහෝ විට එය හොඳ පළමු පියවරකි ; විශේෂයෙන් දෝෂයට අදාළ කේතය මෑතකදී එකතු කර ඇත්නම් (දේශීයව හෝ ප්‍රභව ගබඩාවෙන්).


10

constවිචල්ය ප්‍රකාශන / අර්ථ දැක්වීම්වල "බාහිර" අස්ථානගත වී ඇත (C ++ පමණි)

C වෙතින් පැමිණෙන පුද්ගලයින් සඳහා C ++ ගෝලීය constවිචල්‍යයන්ට අභ්‍යන්තර (හෝ ස්ථිතික) සම්බන්ධතාවයක් තිබීම පුදුමයක් විය හැකිය . C හි මෙය එසේ නොවේ, මන්ද සියලු ගෝලීය විචල්‍යයන් ව්‍යංගයෙන් extern(එනම් staticමූල පදය නොමැති විට).

උදාහරණයක්:

// file1.cpp
const int test = 5;    // in C++ same as "static const int test = 5"
int test2 = 5;

// file2.cpp
extern const int test;
extern int test2;

void foo()
{
 int x = test;   // linker error in C++ , no error in C
 int y = test2;  // no problem
}

නිවැරදි වන්නේ ශීර්ෂ ගොනුවක් භාවිතා කර එය file2.cpp සහ file1.cpp වලට ඇතුළත් කිරීමයි

extern const int test;
extern int test2;

විකල්පයක් ලෙස කෙනෙකුට constfile1.cpp හි විචල්‍යය පැහැදිලි ලෙස ප්‍රකාශ කළ හැකියextern


8

මෙය පිළිගත් බහුවිධ පිළිතුරු සහිත තරමක් පැරණි ප්‍රශ්න වුවද, අපැහැදිලි “නිර්වචනය නොකළ සඳහනක්” දෝෂය නිරාකරණය කරන්නේ කෙසේදැයි බෙදා ගැනීමට මම කැමතියි .

පුස්තකාලවල විවිධ අනුවාදයන්

මම යොමු කිරීමට අන්වර්ථයක් භාවිතා කළෙමි std::filesystem::path: ගොනු පද්ධතිය C ++ 17 සිට සම්මත පුස්තකාලයේ ඇත, නමුත් මගේ වැඩසටහනට C ++ 14 ද සම්පාදනය කිරීමට අවශ්‍ය විය, එබැවින් විචල්‍ය අන්වර්ථයක් භාවිතා කිරීමට මම තීරණය කළෙමි:

#if (defined _GLIBCXX_EXPERIMENTAL_FILESYSTEM) //is the included filesystem library experimental? (C++14 and newer: <experimental/filesystem>)
using path_t = std::experimental::filesystem::path;
#elif (defined _GLIBCXX_FILESYSTEM) //not experimental (C++17 and newer: <filesystem>)
using path_t = std::filesystem::path;
#endif

මට ලිපිගොනු තුනක් ඇති බව කියමු: main.cpp, file.h, file.cpp:

  • file.h # හි < පර්යේෂණාත්මක :: ගොනු පද්ධතිය > ඇතුළත් වන අතර ඉහත කේතය අඩංගු වේ
  • file.cpp , file.h ක්‍රියාත්මක කිරීම, # ඇතුළත් " file.h "
  • main.cpp # හි < ගොනු පද්ධතිය > සහ " file.h " ඇතුළත් වේ

Main.cpp සහ file.h හි භාවිතා කරන විවිධ පුස්තකාල සැලකිල්ලට ගන්න. Main.cpp # < ගොනු පද්ධතිය > ට පසුව " file.h " ඇතුළත් කර ඇති හෙයින් , එහි භාවිතා කරන ලද ගොනු පද්ධතියේ අනුවාදය C ++ 17 එකක් විය . මම පහත දැක්වෙන විධානයන් සමඟ වැඩසටහන සම්පාදනය කිරීමට භාවිතා කළෙමි:

$ g++ -g -std=c++17 -c main.cpp-> සථායිතාව main.cpp main.o කිරීමට
$ g++ -g -std=c++17 -c file.cpp-> file.o කිරීමට file.cpp හා file.h සම්පාදනය
$ g++ -g -std=c++17 -o executable main.o file.o -lstdc++fs-> සබැඳි main.o හා file.o

මේ ආකාරයට ඕනෑම උත්සවයකට බව file.o අඩංගු හා main.o භාවිතා අවශ්යpath_t නිසා "නිර්වචනය නොකළ සඳහනක්" දෝෂ දුන් main.o සඳහන් std::filesystem::pathනමුත් file.o කිරීමට std::experimental::filesystem::path.

විභේදනය

මෙය නිවැරදි කිරීම සඳහා මට අවශ්‍ය වූයේ <පර්යේෂණාත්මක :: ගොනු පද්ධතිය> file.h හි <filesystem> ලෙස වෙනස් කිරීමයි.


5

හවුල් පුස්තකාල සමඟ සම්බන්ධ වන විට, භාවිතා කළ සංකේත සැඟවී නොමැති බවට වග බලා ගන්න.

Gcc හි පෙරනිමි හැසිරීම නම් සියලු සංකේත දෘශ්‍යමාන වීමයි. කෙසේ වෙතත්, පරිවර්තන ඒකක විකල්පයක් සහිතව ගොඩනඟා ඇති විට, එහි ප්‍රති shared ලයක් ලෙස බෙදාගත් වස්තුවෙහි බාහිර වන්නේ -fvisibility=hiddenසලකුණු කර __attribute__ ((visibility ("default")))ඇති ශ්‍රිත / සංකේත පමණි .

ආයාචනා කිරීමෙන් ඔබ සොයන සංකේත බාහිරද යන්න ඔබට පරීක්ෂා කළ හැකිය:

# -D shows (global) dynamic symbols that can be used from the outside of XXX.so
nm -D XXX.so | grep MY_SYMBOL 

සැඟවුණු / දේශීය සංකේත nmකුඩා අකුරු සංකේතයකින් පෙන්වනු ලැබේ , උදාහරණයක් ලෙස tකේත කොටස සඳහා `ටී වෙනුවට:

nm XXX.so
00000000000005a7 t HIDDEN_SYMBOL
00000000000005f8 T VISIBLE_SYMBOL

නම් විකෘති nmකිරීමේ විකල්පය සමඟද ඔබට භාවිතා කළ හැකිය -C(C ++ භාවිතා කළේ නම්).

වින්ඩෝස්-ඩීඑල්එස් වලට සමානව, යමෙකු පොදු කාර්යයන් අර්ථ දැක්වීමකින් සලකුණු කරයි, උදාහරණයක් ලෙස DLL_PUBLICඅර්ථ දැක්වෙන්නේ:

#define DLL_PUBLIC __attribute__ ((visibility ("default")))

DLL_PUBLIC int my_public_function(){
  ...
}

එය දළ වශයෙන් වින්ඩෝස් / එම්එස්වීසී අනුවාදයට අනුරූප වේ:

#ifdef BUILDING_DLL
    #define DLL_PUBLIC __declspec(dllexport) 
#else
    #define DLL_PUBLIC __declspec(dllimport) 
#endif

දෘශ්‍යතාව පිළිබඳ වැඩි විස්තර gcc විකියෙන් සොයාගත හැකිය.


පරිවර්තන ඒකකයක් සම්පාදනය කරන -fvisibility=hiddenවිට ලැබෙන සංකේත වලට තවමත් බාහිර සම්බන්ධතා ඇත (ඉහළ අක්ෂර සංකේත වර්ගය අනුව පෙන්වා ඇත nm) සහ වස්තු ලිපිගොනු ස්ථිතික පුස්තකාලයක කොටසක් බවට පත්වුවහොත් ගැටළුවක් නොමැතිව බාහිර සම්බන්ධතා සඳහා භාවිතා කළ හැකිය. සම්බන්ධතාවය දේශීය බවට පත්වන්නේ වස්තු ලිපිගොනු හවුල් පුස්තකාලයකට සම්බන්ධ කළ විට පමණි.

වස්තු ගොනුවක සැඟවී ඇති සංකේත මොනවාදැයි සොයා ගැනීමට:

>>> objdump -t XXXX.o | grep hidden
0000000000000000 g     F .text  000000000000000b .hidden HIDDEN_SYMBOL1
000000000000000b g     F .text  000000000000000b .hidden HIDDEN_SYMBOL2

ඔබ බාහිර සංකේත භාවිතා කිරීම nm -CDහෝ nm -gCDබැලීම කළ යුතුය . GCC විකියේ දෘශ්‍යතාවද බලන්න .
jww

2

විවිධ ගෘහ නිර්මාණ

ඔබට මෙවැනි පණිවිඩයක් දැකිය හැකිය:

library machine type 'x64' conflicts with target machine type 'X86'

එවැනි අවස්ථාවක, එයින් අදහස් කරන්නේ පවතින සංකේත ඔබ සම්පාදනය කරන මෝස්තරයට වඩා වෙනස් ගෘහ නිර්මාණ ශිල්පයක් සඳහා බවයි.

විෂුවල් ස්ටුඩියෝ හි, මෙය වැරදි "වේදිකාව" නිසා වන අතර, ඔබට සුදුසු එකක් තෝරා ගැනීමට හෝ පුස්තකාලයේ නිසි අනුවාදය ස්ථාපනය කිරීමට අවශ්‍ය වේ.

ලිනක්ස් හි, එය වැරදි පුස්තකාල ෆෝල්ඩරයක් නිසා විය හැකිය ( නිදසුනක් libවෙනුවට භාවිතා කිරීම lib64).

MacOS හි, ගෘහ නිර්මාණ දෙකම එකම ගොනුවක නැව්ගත කිරීමේ විකල්පයක් ඇත. සමහර විට සබැඳිය අනුවාද දෙකම එහි තිබිය යුතු යැයි අපේක්ෂා කරයි, නමුත් එකක් පමණි. එය පුස්තකාලය ලබා ගන්නා වැරදි lib/ lib64ෆෝල්ඩරයේ ගැටළුවක් ද විය හැකිය .

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.