ප්‍රභව ලිපිගොනු අතර විචල්‍යයන් බෙදා ගැනීමට මම බාහිර භාවිතා කරන්නේ කෙසේද?


1010

C හි ගෝලීය විචල්‍යයන්ට සමහර විට externමූලික පදය ඇති බව මම දනිමි . externවිචල්යයක් යනු කුමක්ද? ප්‍රකාශය මොන වගේද? එහි විෂය පථය කුමක්ද?

මෙය ප්‍රභව ලිපිගොනු හරහා විචල්‍යයන් බෙදා ගැනීම හා සම්බන්ධ වේ, නමුත් එය හරියටම ක්‍රියාත්මක වන්නේ කෙසේද? මා භාවිතා කරන්නේ කොතැනින්ද extern?

Answers:


1786

භාවිතා externකිරීම අදාළ වන්නේ ඔබ ගොඩනඟන වැඩසටහන එකට සම්බන්ධ වී ඇති බහු මූලාශ්‍ර ලිපිගොනු වලින් වන අතර, එහිදී සමහර විචල්‍යයන් අර්ථ දක්වා ඇත, නිදසුනක් ලෙස, ප්‍රභව ගොනුවේ file1.cවෙනත් මූලාශ්‍ර ලිපිගොනු වල සඳහන් කිරීම අවශ්‍ය වේ file2.c.

එය වැදගත් වේ අතර ඇති වෙනස තේරුම් නිර්වචනය විචල්ය හා ප්රකාශ විචල්ය :

  • විචල්‍යයක් පවතින බව සම්පාදකයාට දන්වන විට විචල්‍යයක් ප්‍රකාශයට පත් කෙරේ (මෙය එහි වර්ගයයි); එය එම අවස්ථාවේදී විචල්‍යය සඳහා ආචයනය වෙන් නොකරයි.

  • සම්පාදකයා විචල්‍යය සඳහා ආචයනය වෙන් කරන විට විචල්‍යයක් අර්ථ දැක්වේ .

ඔබට විචල්‍යය කිහිප වතාවක් ප්‍රකාශ කළ හැකිය (වරක් ප්‍රමාණවත් වුවද); ඔබට එය අර්ථ දැක්විය හැක්කේ යම් විෂය පථයක් තුළ එක් වරක් පමණි. විචල්ය අර්ථ දැක්වීමක් ද ප්රකාශයකි, නමුත් සියලු විචල්ය ප්රකාශයන් අර්ථ දැක්වීම් නොවේ.

ගෝලීය විචල්‍යයන් ප්‍රකාශ කිරීමට සහ අර්ථ දැක්වීමට හොඳම ක්‍රමය

ගෝලීය විචල්යයන් ප්රකාශ කිරීමට හා අර්ථ දැක්වීමට පිරිසිදු, විශ්වසනීය ක්රමය වන්නේ විචල්යයේ extern ප්රකාශයක් අඩංගු කිරීම සඳහා ශීර්ෂ ගොනුවක් භාවිතා කිරීමයි .

විචල්‍යය නිර්වචනය කරන එක් ප්‍රභව ගොනුවක් සහ විචල්‍යය සඳහන් කරන සියලුම ප්‍රභව ගොනු මගින් ශීර්ෂකය ඇතුළත් වේ. සෑම වැඩසටහනක් සඳහාම, එක් ප්‍රභව ගොනුවක් (සහ එක් ප්‍රභව ගොනුවක් පමණක්) විචල්‍යය අර්ථ දක්වයි. ඒ හා සමානව, එක් ශීර්ෂ ගොනුවක් (සහ එක් ශීර්ෂ ගොනුවක් පමණක්) විචල්‍යය ප්‍රකාශ කළ යුතුය. ශීර්ෂ ගොනුව ඉතා වැදගත් ය; එය ස්වාධීන TUs (පරිවර්තන ඒකක - මූලාශ්‍ර ලිපිගොනු සිතන්න) අතර හරස් පරීක්‍ෂා කිරීමට ඉඩ සලසයි.

එය කිරීමට වෙනත් ක්‍රම තිබුණද, මෙම ක්‍රමය සරල හා විශ්වාසදායකය. එය නිරූපණය කරන්නේ file3.h, file1.cසහ file2.c:

file3.h

extern int global_variable;  /* Declaration of the variable */

file1.c

#include "file3.h"  /* Declaration made available here */
#include "prog1.h"  /* Function declarations */

/* Variable defined here */
int global_variable = 37;    /* Definition checked against declaration */

int increment(void) { return global_variable++; }

file2.c

#include "file3.h"
#include "prog1.h"
#include <stdio.h>

void use_it(void)
{
    printf("Global variable: %d\n", global_variable++);
}

ගෝලීය විචල්‍යයන් ප්‍රකාශ කිරීමට හා අර්ථ දැක්වීමට හොඳම ක්‍රමය එයයි.


ඊළඟ ලිපිගොනු දෙක සඳහා මූලාශ්‍රය සම්පූර්ණ කරයි prog1:

සම්පූර්ණ වැඩසටහන් භාවිත ශ්‍රිත භාවිතා කරයි, එබැවින් ශ්‍රිත ප්‍රකාශන ක්‍රියාත්මක වී ඇත. C99 සහ C11 යන දෙකටම ඒවා භාවිතා කිරීමට පෙර ප්‍රකාශ කිරීම හෝ නිර්වචනය කිරීම අවශ්‍ය වේ (C90 එසේ නොකළ නමුත් හොඳ හේතු නිසා). externශීර්ෂයන්හි externවිචල්‍ය ප්‍රකාශන ඉදිරියේ ගැලපීම සඳහා මම ශීර්ෂයන්හි ක්‍රියාකාරී ප්‍රකාශන ඉදිරිපිට යතුරු පදය භාවිතා කරමි . බොහෝ අය externක්‍රියාකාරී ප්‍රකාශ ඉදිරියේ භාවිතා නොකිරීමට කැමැත්තක් දක්වයි ; සම්පාදකයා එය ගණන් ගන්නේ නැත - අවසාන වශයෙන්, ඔබ ස්ථාවර වන තාක් කල්, අවම වශයෙන් ප්‍රභව ගොනුවක් තුළවත් මම නොසිටිමි.

prog1.h

extern void use_it(void);
extern int increment(void);

prog1.c

#include "file3.h"
#include "prog1.h"
#include <stdio.h>

int main(void)
{
    use_it();
    global_variable += 19;
    use_it();
    printf("Increment: %d\n", increment());
    return 0;
}
  • prog1භාවිතා prog1.c, file1.c, file2.c, file3.hහා prog1.h.

ගොනුව පමණක් prog1.mkmakefile වේ prog1. makeසහස්‍රයේ ආරම්භයේ සිට නිපදවන ලද බොහෝ සංස්කරණ සමඟ එය ක්‍රියා කරනු ඇත . එය විශේෂයෙන් GNU Make සමඟ බැඳී නොමැත.

prog1.mk

# Minimal makefile for prog1

PROGRAM = prog1
FILES.c = prog1.c file1.c file2.c
FILES.h = prog1.h file3.h
FILES.o = ${FILES.c:.c=.o}

CC      = gcc
SFLAGS  = -std=c11
GFLAGS  = -g
OFLAGS  = -O3
WFLAG1  = -Wall
WFLAG2  = -Wextra
WFLAG3  = -Werror
WFLAG4  = -Wstrict-prototypes
WFLAG5  = -Wmissing-prototypes
WFLAGS  = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5}
UFLAGS  = # Set on command line only

CFLAGS  = ${SFLAGS} ${GFLAGS} ${OFLAGS} ${WFLAGS} ${UFLAGS}
LDFLAGS =
LDLIBS  =

all:    ${PROGRAM}

${PROGRAM}: ${FILES.o}
    ${CC} -o $@ ${CFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}

prog1.o: ${FILES.h}
file1.o: ${FILES.h}
file2.o: ${FILES.h}

# If it exists, prog1.dSYM is a directory on macOS
DEBRIS = a.out core *~ *.dSYM
RM_FR  = rm -fr

clean:
    ${RM_FR} ${FILES.o} ${PROGRAM} ${DEBRIS}

මාර්ගෝපදේශ

විශේෂ experts යින් විසින් පමණක් බිඳ දැමිය යුතු නීති, සහ හොඳ හේතු සහිතව පමණි:

  • ශීර්ෂ ගොනුවක අඩංගු externවන්නේ විචල්‍ය ප්‍රකාශයන් පමණි - කිසි විටෙක staticහෝ සුදුසුකම් නොලත් විචල්‍ය අර්ථ දැක්වීම්.

  • ඕනෑම විචල්‍යයක් සඳහා, එය ප්‍රකාශ කරන්නේ එක් ශීර්ෂ ගොනුවක් පමණි (SPOT - Single Point of Truth).

  • ප්‍රභව ගොනුවක කිසි විටෙක externවිචල්‍ය ප්‍රකාශ අඩංගු නොවේ - ප්‍රභව ලිපිගොනු සෑම විටම ඒවා ප්‍රකාශ කරන (එකම) ශීර්ෂය ඇතුළත් වේ.

  • ඕනෑම විචල්‍යයක් සඳහා, හරියටම එක් ප්‍රභව ගොනුවක් විචල්‍යය නිර්වචනය කරයි. (පැහැදිලිවම ශුන්‍යයට ආරම්භ කිරීමේ අවශ්‍යතාවයක් නොතිබුණද, එයින් කිසිදු හානියක් සිදු නොවන අතර හොඳක් කළ හැකිය. මන්දයත් වැඩසටහනක නිශ්චිත ගෝලීය විචල්‍යයක් සඳහා ආරම්භක අර්ථ දැක්වීමක් පමණක් තිබිය හැකි බැවිනි).

  • විචල්‍යය නිර්වචනය කරන ප්‍රභව ගොනුවට අර්ථ දැක්වීම සහ ප්‍රකාශනය අනුකූල බව සහතික කිරීම සඳහා ශීර්ෂකය ද ඇතුළත් වේ.

  • ශ්‍රිතයක් කිසි විටෙක විචල්‍යයක් භාවිතා කරමින් ප්‍රකාශ කිරීමට අවශ්‍ය නොවිය යුතුය extern.

  • හැකි සෑම විටම ගෝලීය විචල්‍යයන්ගෙන් වළකින්න - ඒ වෙනුවට කාර්යයන් භාවිතා කරන්න.

මෙම පිළිතුරේ ප්‍රභව කේතය සහ පෙළ src / so-0143-3204 උප බහලුමේ ඇති GitHub හි මගේ SOQ (Stack Overflow Questions) ගබඩාවේ ඇත .

ඔබ පළපුරුදු සී ක්‍රමලේඛකයෙකු නොවේ නම්, ඔබට මෙහි කියවීම නැවැත්විය හැකිය (සමහර විට).

ගෝලීය විචල්‍යයන් නිර්වචනය කිරීමට එතරම් හොඳ ක්‍රමයක් නොවේ

සමහර (ඇත්ත වශයෙන්ම, බොහෝ) සී සම්පාදකයන් සමඟ, විචල්‍යයක 'පොදු' අර්ථ දැක්වීමෙන් ද ඔබට ගැලවිය හැකිය. 'පොදු', මෙහි, ෆෝට්රාන් හි මූලාශ්‍ර ලිපිගොනු අතර විචල්‍යයන් හුවමාරු කර ගැනීම සඳහා භාවිතා කරන තාක්‍ෂණයකි. මෙහි සිදුවන්නේ එක් එක් ලිපිගොනු ගණන විචල්‍යය පිළිබඳ තාවකාලික අර්ථ දැක්වීමකි. එක් ගොනුවකට වඩා ආරම්භක අර්ථ දැක්වීමක් ලබා නොදෙන තාක් කල්, විවිධ ලිපිගොනු විචල්‍යයේ පොදු තනි අර්ථ දැක්වීමක් බෙදා ගනී:

file10.c

#include "prog2.h"

long l;   /* Do not do this in portable code */

void inc(void) { l++; }

file11.c

#include "prog2.h"

long l;   /* Do not do this in portable code */

void dec(void) { l--; }

file12.c

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

long l = 9;   /* Do not do this in portable code */

void put(void) { printf("l = %ld\n", l); }

මෙම තාක්ෂණය සී ප්‍රමිතියේ අකුරට හා 'එක් අර්ථ දැක්වීමේ රීතියට' අනුකූල නොවේ - එය නිල වශයෙන් නිර්වචනය නොකළ හැසිරීමකි:

J.2 නිර්වචනය නොකළ හැසිරීම

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

§6.9 බාහිර අර්ථ දැක්වීම් ¶5

බාහිර අර්ථ දැක්වීම ද කාර්යය (ක පේළිගත අර්ථ දැක්වීම හැර) හෝ වස්තුවක් පිළිබඳ අර්ථ නිරූපනයක් බව බාහිර ප්රකාශ කිරීමකි. බාහිර සම්බන්ධතාවයකින් ප්‍රකාශිත හඳුනාගැනීමක් ප්‍රකාශනයක භාවිතා කරන්නේ නම් (ප්‍රති result ල පූර්ණ සංඛ්‍යා නියතයක් වන ක්‍රියාකරුගේ sizeofහෝ _Alignofක්‍රියාකරුගේ ක්‍රියාකාරිත්වයේ කොටසක් හැර ), සමස්ත වැඩසටහනේ කොතැනක හෝ හඳුනාගැනීමේ යන්ත්‍රයට හරියටම එක් බාහිර අර්ථ දැක්වීමක් තිබිය යුතුය; එසේ නොමැති නම්, එකකට වඩා තිබිය යුතු නොවේ. 161)

161) මේ අනුව, ප්‍රකාශනයක බාහිර සම්බන්ධතාවයකින් ප්‍රකාශිත හඳුනාගැනීමක් භාවිතා නොකරන්නේ නම්, ඒ සඳහා බාහිර අර්ථ දැක්වීමක් අවශ්‍ය නොවේ.

කෙසේ වෙතත්, සී ප්‍රමිතිය එය තොරතුරු දිග ඇනෙක්ස් ජේ හි පොදු දිගුවක් ලෙස ලැයිස්තුගත කරයි .

J.5.11 බහු බාහිර අර්ථ දැක්වීම්

වස්තුවක් හදුනා ගැනීම සඳහා බාහිර අර්ථ දැක්වීම් එකකට වඩා තිබිය හැකිය, බාහිර වචන පදය පැහැදිලිව භාවිතා කිරීම හෝ රහිතව; අර්ථ දැක්වීම් එකඟ නොවන්නේ නම් හෝ එකකට වඩා ආරම්භ කර ඇත්නම්, හැසිරීම නිර්වචනය නොකෙරේ (6.9.2).

මෙම තාක්ෂණය සැමවිටම සහාය නොදක්වන බැවින්, එය භාවිතා කිරීමෙන් වැළකී සිටීම වඩාත් සුදුසුය, විශේෂයෙන් ඔබේ කේතය අතේ ගෙන යා හැකි නම් . මෙම තාක්‍ෂණය භාවිතා කිරීමෙන් ඔබට නොදැනුවත්වම ද pun ුවම් පැමිණවිය හැකිය.

ඉහත ලිපිගොනු වලින් එකක් ඒ වෙනුවට ආදේශකයක් lලෙස ප්‍රකාශයට පත් කළ හොත් , සී වර්ගයේ අනාරක්ෂිත සම්බන්ධකයන් නොගැලපීම හඳුනා නොගනී. ඔබ 64-bit සමග පරිගණකයේ නම් හා , ඔබ පවා අනතුරු ඇඟවීමක් ලබා ගැනීමට නොහැකි කැමතියි; 32-බිට් සහ 64-බිට් සහිත යන්ත්‍රයක , ඔබට විවිධ ප්‍රමාණ ගැන අනතුරු ඇඟවීමක් ලැබෙනු ඇත - සම්බන්ධකය විශාලතම ප්‍රමාණය භාවිතා කරනු ඇත, හරියටම ෆෝට්රාන් වැඩසටහනක් ඕනෑම පොදු කුට්ටි වල විශාලතම ප්‍රමාණය ගනී.doublelonglongdoublelongdouble

2020-05-07 දින නිකුත් කරන ලද GCC 10.1.0, භාවිතා කිරීමට පෙරනිමි සම්පාදන විකල්පයන් වෙනස් කරන බව සලකන්න, -fno-commonඑයින් අදහස් වන්නේ පෙරනිමියෙන් ඔබ පෙරනිමිය ඉක්මවා නොයන්නේ නම් -fcommon(හෝ ගුණාංග භාවිතා කිරීම යනාදිය) - සබැඳිය බලන්න).


ඊළඟ ලිපිගොනු දෙක සඳහා මූලාශ්‍රය සම්පූර්ණ කරයි prog2:

prog2.h

extern void dec(void);
extern void put(void);
extern void inc(void);

prog2.c

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

int main(void)
{
    inc();
    put();
    dec();
    put();
    dec();
    put();
}
  • prog2භාවිතා prog2.c, file10.c, file11.c, file12.c, prog2.h.

අවවාදයයි

මෙහි අදහස් දැක්වීම්වල සඳහන් කර ඇති පරිදි, ඒ හා සමාන ප්‍රශ්නයකට මගේ පිළිතුරෙහි සඳහන් කර ඇති පරිදි , ගෝලීය විචල්‍යයක් සඳහා බහුවිධ නිර්වචන භාවිතා කිරීම නිර්වචනය නොකළ හැසිරීමට තුඩු දෙයි (J.2; .6.9), එය “ඕනෑම දෙයක් සිදුවිය හැකිය” යනුවෙන් සම්මතයේ ක්‍රමයයි. සිදුවිය හැකි එක් දෙයක් නම්, වැඩසටහන ඔබ අපේක්ෂා කළ පරිදි ක්‍රියා කිරීමයි; සහ J.5.11, දළ වශයෙන්, "ඔබ ලැබීමට වඩා බොහෝ විට ඔබ වාසනාවන්ත විය හැකිය". නමුත් බාහිර විචල්‍යයක බහුවිධ නිර්වචන මත රඳා පවතින වැඩසටහනක් - පැහැදිලි 'බාහිර' මූල පදය සමඟ හෝ නැතිව - දැඩි ලෙස අනුකූල වන වැඩසටහනක් නොවන අතර සෑම තැනකම වැඩ කිරීමට සහතික නොවේ. සමානව: එය පෙන්විය හැකි හෝ නොපෙන්වන දෝෂයක් අඩංගු වේ.

මාර්ගෝපදේශ උල්ලං ting නය කිරීම

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

දෝෂ සහිත_හෙඩර්.එච්

int some_var;    /* Do not do this in a header!!! */

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

break_header.h

int some_var = 13;    /* Only one source file in a program can use this */

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

seldom_correct.h

static int hidden_global = 3;   /* Each source file gets its own copy  */

සටහන 3: ශීර්ෂකය ස්ථිතික විචල්‍යයක් නිර්වචනය කරන්නේ නම් (ආරම්භය සමඟ හෝ රහිතව), එවිට සෑම ප්‍රභව ගොනුවක්ම 'ගෝලීය' විචල්‍යයේ පුද්ගලික අනුවාදය සමඟ අවසන් වේ.

විචල්‍යය සැබවින්ම සංකීර්ණ අරාවක් නම්, උදාහරණයක් ලෙස, මෙය කේතයේ අන්ත අනුපිටපතකට තුඩු දිය හැකිය. එය, ඉඳහිට, යම් බලපෑමක් ලබා ගැනීම සඳහා සංවේදී ක්‍රමයක් විය හැකි නමුත් එය ඉතා අසාමාන්‍යය.


සාරාංශය

මා මුලින් පෙන්වූ ශීර්ෂ තාක්ෂණය භාවිතා කරන්න. එය විශ්වසනීයව හා සෑම තැනකම ක්රියා කරයි. විශේෂයෙන් ශීර්ෂකය ප්‍රකාශයට පත් කරන බව සලකන්නglobal_variable එය භාවිතා කරන සෑම ගොනුවකම ඇතුළත් කර ඇති . සෑම දෙයක්ම ස්වයං-අනුකූල බව මෙයින් සහතික කෙරේ.

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

මුල් පිළිතුරේ අවසානය

ඔබ පළපුරුදු සී ක්‍රමලේඛකයෙකු නොවේ නම්, ඔබ බොහෝ විට මෙහි කියවීම නැවැත්විය යුතුය.


ප්රධාන ප්රධාන එකතු කිරීම

කේත අනුපිටපත් කිරීමෙන් වළකින්න

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

තවත් කරුණක් නම්, එක් එක් 'ප්‍රධාන වැඩසටහන්' ගණනක විචල්‍යයන් නිර්වචනය කළ යුතු බවයි. මෙය සාමාන්‍යයෙන් ව්‍යාජ කරුණකි; විචල්‍යයන් නිර්වචනය කිරීමට සහ එක් එක් වැඩසටහන් සමඟ නිපදවන වස්තු ගොනුව සම්බන්ධ කිරීමට ඔබට සී ප්‍රභව ගොනුවක් හඳුන්වා දිය හැකිය.

මෙහි දක්වා ඇති මුල් ගෝලීය විචල්‍යය භාවිතා කරමින් සාමාන්‍ය යෝජනා ක්‍රමයක් මේ ආකාරයට ක්‍රියා කරයි file3.h:

file3a.h

#ifdef DEFINE_VARIABLES
#define EXTERN /* nothing */
#else
#define EXTERN extern
#endif /* DEFINE_VARIABLES */

EXTERN int global_variable;

file1a.c

#define DEFINE_VARIABLES
#include "file3a.h"  /* Variable defined - but not initialized */
#include "prog3.h"

int increment(void) { return global_variable++; }

file2a.c

#include "file3a.h"
#include "prog3.h"
#include <stdio.h>

void use_it(void)
{
    printf("Global variable: %d\n", global_variable++);
}

ඊළඟ ලිපිගොනු දෙක සඳහා මූලාශ්‍රය සම්පූර්ණ කරයි prog3:

prog3.h

extern void use_it(void);
extern int increment(void);

prog3.c

#include "file3a.h"
#include "prog3.h"
#include <stdio.h>

int main(void)
{
    use_it();
    global_variable += 19;
    use_it();
    printf("Increment: %d\n", increment());
    return 0;
}
  • prog3භාවිතා prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.

විචල්ය ආරම්භය

පෙන්වා ඇති පරිදි මෙම යෝජනා ක්‍රමයේ ඇති ගැටළුව නම් එය ගෝලීය විචල්‍යය ආරම්භ කිරීම සඳහා ලබා නොදීමයි. C99 හෝ C11 සහ මැක්‍රෝස් සඳහා විචල්‍ය තර්ක ලැයිස්තු සමඟ, ඔබට ආරම්භයට සහය දැක්වීම සඳහා සාර්ව අර්ථ දැක්විය හැකිය. (C89 සහ මැක්‍රෝස් වල විචල්‍ය තර්ක ලැයිස්තු සඳහා සහය නොදක්වන හෙයින්, අත්තනෝමතික ලෙස දිගු ආරම්භකයින් හැසිරවීමට පහසු ක්‍රමයක් නොමැත.)

file3b.h

#ifdef DEFINE_VARIABLES
#define EXTERN                  /* nothing */
#define INITIALIZER(...)        = __VA_ARGS__
#else
#define EXTERN                  extern
#define INITIALIZER(...)        /* nothing */
#endif /* DEFINE_VARIABLES */

EXTERN int global_variable INITIALIZER(37);
EXTERN struct { int a; int b; } oddball_struct INITIALIZER({ 41, 43 });

ඩෙනිස් ක්නියාෂෙව් විසින් හඳුනාගෙන ඇති දෝෂ නිවැරදි කිරීම #ifසහ අන්තර්ගතය ආපසු හරවන්න#else

file1b.c

#define DEFINE_VARIABLES
#include "file3b.h"  /* Variables now defined and initialized */
#include "prog4.h"

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

file2b.c

#include "file3b.h"
#include "prog4.h"
#include <stdio.h>

void use_them(void)
{
    printf("Global variable: %d\n", global_variable++);
    oddball_struct.a += global_variable;
    oddball_struct.b -= global_variable / 2;
}

ඔඩ්බෝල් ව්‍යුහය සඳහා වන කේතය ඔබ සාමාන්‍යයෙන් ලිවීමට කැමති දෙයක් නොවන බව පැහැදිලිය. දෙවන පිහිට පැතීමක් කළ පළමු තර්කය INITIALIZERවන්නේ { 41අතර ඉතිරි තර්කය (මෙම උදාහරණය තුල ඒක වචන) යනු 43 }. C99 හෝ මැක්‍රෝස් සඳහා විචල්‍ය තර්ක ලැයිස්තු සඳහා සමාන සහය නොමැතිව, කොමාව අඩංගු කළ යුතු ආරම්භකයින් ඉතා ගැටළු සහගතය.

ඩෙනිස් ක්නියාෂෙව්ට නිවැරදි ශීර්ෂකය file3b.hඇතුළත් කර ඇත (වෙනුවට fileba.h)


ඊළඟ ලිපිගොනු දෙක සඳහා මූලාශ්‍රය සම්පූර්ණ කරයි prog4:

prog4.h

extern int increment(void);
extern int oddball_value(void);
extern void use_them(void);

prog4.c

#include "file3b.h"
#include "prog4.h"
#include <stdio.h>

int main(void)
{
    use_them();
    global_variable += 19;
    use_them();
    printf("Increment: %d\n", increment());
    printf("Oddball:   %d\n", oddball_value());
    return 0;
}
  • prog4භාවිතා prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.

ශීර්ෂ ආරක්ෂකයින්

ඕනෑම ශීර්ෂයක් නැවත ඇතුළත් කිරීමට එරෙහිව ආරක්ෂා කළ යුතුය, එවිට වර්ග අර්ථ දැක්වීම් (enum, struct හෝ Union වර්ග, හෝ සාමාන්‍යයෙන් typedefs) ගැටළු ඇති නොකරයි. සම්මත තාක්‍ෂණය නම් ශීර්ෂකයේ සිරුර ශීර්ෂ ආරක්ෂකයා තුළ ඔතා තැබීමයි:

#ifndef FILE3B_H_INCLUDED
#define FILE3B_H_INCLUDED

...contents of header...

#endif /* FILE3B_H_INCLUDED */

ශීර්ෂය දෙවරක් වක්‍රව ඇතුළත් කළ හැකිය. නිදසුනක් ලෙස, පෙන්වා නැති ආකාරයේ අර්ථ දැක්වීමක් සඳහා file4b.hඇතුළත් වන්නේ නම් සහ ශීර්ෂකය යන දෙකම භාවිතා කිරීමට අවශ්‍ය file3b.hනම් සහ file1b.cවිසඳීමට ඔබට තවත් උපක්‍රමශීලී ගැටළු කිහිපයක් තිබේ. පැහැදිලිවම, ඔබට ශීර්ෂ ලැයිස්තුව සංශෝධනය කළ හැකිය . කෙසේ වෙතත්, ඔබ අභ්‍යන්තර පරායත්තතාවයන් ගැන නොදැන සිටිය හැකිය - සහ කේතය ඉතා මැනවින් අඛණ්ඩව ක්‍රියාත්මක විය යුතුය.file4b.hfile3b.hfile4b.h

තව දුරටත්, එය අර්ථ දැක්වීමට ඇතුළත් file4b.h කිරීමට පෙර ඔබ ඇතුළත් කළ හැකි නිසා එය ව්‍යාකූල වීමට පටන් ගනී file3b.h, නමුත් සාමාන්‍ය ශීර්ෂක ආරක්ෂකයින් file3b.hවිසින් ශීර්ෂකය නැවත ඇතුළත් කිරීම වලක්වනු ඇත.

එබැවින්, ඔබට file3b.hඑකවරම ශරීරය ප්‍රකාශන සඳහාද, එක් වරක් නිර්වචන සඳහාද ඇතුළත් කළ යුතුය, නමුත් ඔබට තනි පරිවර්තන ඒකකයක (TU - ප්‍රභව ගොනුවක එකතුවක් සහ එය භාවිතා කරන ශීර්ෂයන්) අවශ්‍ය විය හැකිය.

විචල්ය අර්ථ දැක්වීම් සමඟ බහු ඇතුළත් කිරීම

කෙසේ වෙතත්, එය අසාධාරණ නොවන සීමාවකට යටත්ව කළ හැකිය. අපි නව ගොනු නාම මාලාවක් හඳුන්වා දෙමු:

  • external.h බාහිර සාර්ව අර්ථ දැක්වීම් සඳහා.

  • file1c.hවර්ග නිර්වචනය කිරීමට (විශේෂයෙන්, struct oddballවර්ගය oddball_struct).

  • file2c.h ගෝලීය විචල්‍යයන් නිර්වචනය කිරීමට හෝ ප්‍රකාශ කිරීමට.

  • file3c.c එය ගෝලීය විචල්‍යයන් අර්ථ දක්වයි.

  • file4c.c එය සරලවම ගෝලීය විචල්‍යයන් භාවිතා කරයි.

  • file5c.c එයින් පෙන්නුම් කරන්නේ ඔබට ගෝලීය විචල්‍යයන් ප්‍රකාශ කිරීමට හා නිර්වචනය කිරීමට හැකි බවයි.

  • file6c.c එයින් පෙන්නුම් කරන්නේ ඔබට ගෝලීය විචල්‍යයන් නිර්වචනය කර (ප්‍රකාශ කිරීමට උත්සාහ කළ හැකි) බවයි.

මෙම උදාහරණ වලදී, file5c.cසහ file6c.cශීර්ෂය file2c.hකිහිප වතාවක් සෘජුවම ඇතුළත් කරන්න , නමුත් යාන්ත්‍රණය ක්‍රියාත්මක වන බව පෙන්වීමට ඇති සරලම ක්‍රමය එයයි. එහි අර්ථය වන්නේ ශීර්ෂය දෙවරක් වක්‍රව ඇතුළත් කර ඇත්නම් එයද ආරක්ෂිත බවයි.

මෙය ක්‍රියාත්මක වීමට ඇති සීමාවන්:

  1. ගෝලීය විචල්‍යයන් නිර්වචනය කිරීම හෝ ප්‍රකාශ කිරීම සඳහා වන ශීර්ෂකය කිසිදු වර්ගයක් නිර්වචනය නොකරයි.

  2. විචල්‍යයන් නිර්වචනය කළ යුතු ශීර්ෂයක් ඇතුළත් කිරීමට පෙර, ඔබ සාර්ව DEFINE_VARIABLES අර්ථ දක්වයි.

  3. විචල්යයන් නිර්වචනය කිරීම හෝ ප්රකාශ කිරීම ශීර්ෂයෙහි ශෛලීගත අන්තර්ගතයන් ඇත.

external.h

/*
** This header must not contain header guards (like <assert.h> must not).
** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
** based on whether macro DEFINE_VARIABLES is currently defined.
*/
#undef EXTERN
#undef INITIALIZE

#ifdef DEFINE_VARIABLES
#define EXTERN              /* nothing */
#define INITIALIZE(...)     = __VA_ARGS__
#else
#define EXTERN              extern
#define INITIALIZE(...)     /* nothing */
#endif /* DEFINE_VARIABLES */

file1c.h

#ifndef FILE1C_H_INCLUDED
#define FILE1C_H_INCLUDED

struct oddball
{
    int a;
    int b;
};

extern void use_them(void);
extern int increment(void);
extern int oddball_value(void);

#endif /* FILE1C_H_INCLUDED */

file2c.h


/* Standard prologue */
#if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
#undef FILE2C_H_INCLUDED
#endif

#ifndef FILE2C_H_INCLUDED
#define FILE2C_H_INCLUDED

#include "external.h"   /* Support macros EXTERN, INITIALIZE */
#include "file1c.h"     /* Type definition for struct oddball */

#if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

/* Global variable declarations / definitions */
EXTERN int global_variable INITIALIZE(37);
EXTERN struct oddball oddball_struct INITIALIZE({ 41, 43 });

#endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

/* Standard epilogue */
#ifdef DEFINE_VARIABLES
#define FILE2C_H_DEFINITIONS
#endif /* DEFINE_VARIABLES */

#endif /* FILE2C_H_INCLUDED */

file3c.c

#define DEFINE_VARIABLES
#include "file2c.h"  /* Variables now defined and initialized */

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

file4c.c

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

void use_them(void)
{
    printf("Global variable: %d\n", global_variable++);
    oddball_struct.a += global_variable;
    oddball_struct.b -= global_variable / 2;
}

file5c.c


#include "file2c.h"     /* Declare variables */

#define DEFINE_VARIABLES
#include "file2c.h"  /* Variables now defined and initialized */

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

file6c.c


#define DEFINE_VARIABLES
#include "file2c.h"     /* Variables now defined and initialized */

#include "file2c.h"     /* Declare variables */

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

ඊළඟ ප්‍රභව ගොනුව ප්‍රභවය සම්පූර්ණ කරයි (ප්‍රධාන වැඩසටහනක් සපයයි) prog5, prog6සහ prog7:

prog5.c

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

int main(void)
{
    use_them();
    global_variable += 19;
    use_them();
    printf("Increment: %d\n", increment());
    printf("Oddball:   %d\n", oddball_value());
    return 0;
}
  • prog5භාවිතා prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.

  • prog6භාවිතා prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.

  • prog7භාවිතා prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


මෙම යෝජනා ක්රමය බොහෝ ගැටළු මඟහරවා ගනී. ඔබ ගැටළුවකට මුහුණ දෙන්නේ විචල්‍යයන් නිර්වචනය කරන ශීර්ෂයක් (වැනි file2c.h) විචල්‍යයන් අර්ථ දක්වන වෙනත් ශීර්ෂයක් (කියන්න file7c.h) ඇතුළත් කළහොත් පමණි. "එය නොකරන්න" හැර වෙනත් පහසු ක්‍රමයක් නොමැත.

සංශෝධනය file2c.hකිරීමෙන් ඔබට අර්ධ වශයෙන් ගැටලුව විසඳා ගත හැකිය file2d.h:

file2d.h

/* Standard prologue */
#if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
#undef FILE2D_H_INCLUDED
#endif

#ifndef FILE2D_H_INCLUDED
#define FILE2D_H_INCLUDED

#include "external.h"   /* Support macros EXTERN, INITIALIZE */
#include "file1c.h"     /* Type definition for struct oddball */

#if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

/* Global variable declarations / definitions */
EXTERN int global_variable INITIALIZE(37);
EXTERN struct oddball oddball_struct INITIALIZE({ 41, 43 });

#endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

/* Standard epilogue */
#ifdef DEFINE_VARIABLES
#define FILE2D_H_DEFINITIONS
#undef DEFINE_VARIABLES
#endif /* DEFINE_VARIABLES */

#endif /* FILE2D_H_INCLUDED */

ගැටළුව 'ශීර්ෂයට ඇතුළත් විය #undef DEFINE_VARIABLESයුතුද?' ඔබ හෙඩිම සිට පළමුෙවන් හා සමග මොන යම් හෝ නිර්වචනය පිහිට පැතීමක් ආවරණය කරනවා නම් #defineසහ #undef:

#define DEFINE_VARIABLES
#include "file2c.h"
#undef DEFINE_VARIABLES

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

#define HEADER_DEFINING_VARIABLES "file2c.h"
#include "externdef.h"

externdef.h

/*
** This header must not contain header guards (like <assert.h> must not).
** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
** be defined with the name (in quotes - or possibly angle brackets) of
** the header to be included that defines variables when the macro
** DEFINE_VARIABLES is defined.  See also: external.h (which uses
** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
** appropriately).
**
** #define HEADER_DEFINING_VARIABLES "file2c.h"
** #include "externdef.h"
*/

#if defined(HEADER_DEFINING_VARIABLES)
#define DEFINE_VARIABLES
#include HEADER_DEFINING_VARIABLES
#undef DEFINE_VARIABLES
#undef HEADER_DEFINING_VARIABLES
#endif /* HEADER_DEFINING_VARIABLES */

මෙම ඇති සංකීර්ණ, පොඩ්ඩක් ලබා ඇත, නමුත් ආරක්ෂිත බව පෙනේ (භාවිතා file2d.hනොමැති, #undef DEFINE_VARIABLESතුළ file2d.h).

file7c.c

/* Declare variables */
#include "file2d.h"

/* Define variables */
#define HEADER_DEFINING_VARIABLES "file2d.h"
#include "externdef.h"

/* Declare variables - again */
#include "file2d.h"

/* Define variables - again */
#define HEADER_DEFINING_VARIABLES "file2d.h"
#include "externdef.h"

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

file8c.h

/* Standard prologue */
#if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
#undef FILE8C_H_INCLUDED
#endif

#ifndef FILE8C_H_INCLUDED
#define FILE8C_H_INCLUDED

#include "external.h"   /* Support macros EXTERN, INITIALIZE */
#include "file2d.h"     /* struct oddball */

#if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

/* Global variable declarations / definitions */
EXTERN struct oddball another INITIALIZE({ 14, 34 });

#endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

/* Standard epilogue */
#ifdef DEFINE_VARIABLES
#define FILE8C_H_DEFINITIONS
#endif /* DEFINE_VARIABLES */

#endif /* FILE8C_H_INCLUDED */

file8c.c

/* Define variables */
#define HEADER_DEFINING_VARIABLES "file2d.h"
#include "externdef.h"

/* Define variables */
#define HEADER_DEFINING_VARIABLES "file8c.h"
#include "externdef.h"

int increment(void) { return global_variable++; }
int oddball_value(void) { return oddball_struct.a + oddball_struct.b; }

ඊළඟ ලිපිගොනු දෙක සඳහා මූලාශ්‍රය සම්පූර්ණ කරන්නේ prog8සහ prog9:

prog8.c

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

int main(void)
{
    use_them();
    global_variable += 19;
    use_them();
    printf("Increment: %d\n", increment());
    printf("Oddball:   %d\n", oddball_value());
    return 0;
}

file9c.c

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

void use_them(void)
{
    printf("Global variable: %d\n", global_variable++);
    oddball_struct.a += global_variable;
    oddball_struct.b -= global_variable / 2;
}
  • prog8භාවිතා prog8.c, file7c.c, file9c.c.

  • prog9භාවිතා prog8.c, file8c.c, file9c.c.


කෙසේ වෙතත්, ගැටළු ප්‍රායෝගිකව සිදුවීමට ඉඩක් නැත, විශේෂයෙන් ඔබ සම්මත උපදෙස් ලබා ගන්නේ නම්

ගෝලීය විචල්‍යයන්ගෙන් වළකින්න


මෙම ප්‍රදර්ශනයෙන් කිසිවක් මග හැරී තිබේද?

_Confession_: මෙහි දක්වා ඇති 'අනුපිටපත් මග හැරීමේ' යෝජනා ක්‍රමය සංවර්ධනය කර ඇත්තේ මෙම ගැටළුව මා වැඩ කරන (නමුත් අයිති නැති) සමහර කේත වලට බලපාන හෙයිනි, සහ පිළිතුරේ පළමු කොටසේ දක්වා ඇති යෝජනා ක්‍රමය පිළිබඳ නොසැලකිලිමත් සැලකිල්ලකි. කෙසේ වෙතත්, මුල් යෝජනා ක්‍රමය මඟින් විචල්‍ය අර්ථ දැක්වීම් සහ ප්‍රකාශන සමමුහුර්තව තබා ගැනීම සඳහා වෙනස් කිරීමට ස්ථාන දෙකක් පමණක් ඉතිරිව ඇති අතර, එය කේත පදනම පුරා විසිරී ඇති බාහිර විචල්‍ය ප්‍රකාශයන් තිබීමට වඩා විශාල ඉදිරි පියවරකි (මුළු ලිපිගොනු දහස් ගණනක් ඇති විට එය සැබවින්ම වැදගත් වේ) . කෙසේ වෙතත්, ලිපිගොනු වල `fileNc. [Ch]` (ඊට අමතරව `external.h` සහ` externdef.h`) නම් සහිත කේතය පෙන්නුම් කරන්නේ එය ක්‍රියාත්මක කළ හැකි බවයි. පැහැදිලිවම, විචල්ය නිර්වචනය හා ප්රකාශ කරන ශීර්ෂ ගොනුවක් සඳහා ප්රමිතිගත අච්චුවක් ඔබට ලබා දීම සඳහා ශීර්ෂ උත්පාදක ස්ක්‍රිප්ටයක් සෑදීම දුෂ්කර නොවනු ඇත.

සැ.යු: මේවා සෙල්ලම් වැඩසටහන් වන අතර ඒවා සුළු වශයෙන් සිත්ගන්නා සුළු කේතයක් ඇත. ඉවත් කළ හැකි උදාහරණ තුළ පුනරාවර්තනයක් ඇත, නමුත් අධ්‍යාපනික පැහැදිලි කිරීම සරල කිරීම නොවේ. (නිදසුනක් ලෙස: ඇතුළත් කර ඇති එක් ශීර්ෂයක නම prog5.cසහ prog8.cඑය අතර වෙනස වේ. main()ශ්‍රිතය නැවත නොකිරීමට කේතය ප්‍රතිසංවිධානය කිරීමට හැකි වනු ඇත , නමුත් එය හෙළි කළ ප්‍රමාණයට වඩා එය සඟවනු ඇත.)


3
it ලිට්බ්: පොදු අර්ථ දැක්වීම සඳහා ඇමුණුම J.5.11 බලන්න - එය පොදු දිගුවකි.
ජොනතන් ලෙෆ්ලර්

3
it ලිට්බ්: එය වළක්වා ගත යුතු යැයි මම එකඟ වෙමි - ඒ නිසා එය 'ගෝලීය විචල්‍යයන් නිර්වචනය කිරීමට එතරම් හොඳ ක්‍රමයක් නොවේ' යන කොටසේ ඇත.
ජොනතන් ලෙෆ්ලර්

3
ඇත්ත වශයෙන්ම එය පොදු දිගුවකි, නමුත් වැඩසටහනක් මත රඳා සිටීම නිර්වචනය නොකළ හැසිරීමකි. සී ගේ නීති රීති අනුව මෙය අවසර දී ඇති බව ඔබ පැවසුවාදැයි මට පැහැදිලි නැත. දැන් මට පෙනේ ඔබ එය පොදු දිගුවක් පමණක් බවත් ඔබේ කේතය අතේ ගෙන යා හැකි නම් එය වළක්වා ගන්න. ඒ නිසා මට සැකයකින් තොරව ඔබව උසස් කළ හැකිය. ඇත්තෙන්ම විශිෂ්ට පිළිතුර IMHO :)
ජොහැන්නස් ෂෝබ් - litb

19
ඔබ ඉහළින් නතර කළහොත්, එය සරල දේවල් සරල ලෙස තබා ගනී. ඔබ තව දුරටත් කියවන විට, එය තවත් සියුම්, සංකූලතා සහ විස්තර සමඟ කටයුතු කරයි. අඩු පළපුරුදු සී ක්‍රමලේඛකයින් සඳහා - හෝ දැනටමත් විෂය දන්නා සී ක්‍රමලේඛකයින් සඳහා මම 'මුල් නැවතුම් ස්ථාන' දෙකක් එකතු කර ඇත්තෙමි. ඔබ දැනටමත් පිළිතුර දන්නවා නම් ඒ සියල්ල කියවීමට අවශ්‍ය නැත (නමුත් ඔබ තාක්ෂණික දෝෂයක් සොයා ගන්නේ නම් මට දන්වන්න).
ජොනතන් ලෙෆ්ලර්

4
up සුපර්කැට්: අරාවෙහි විශාලත්වය සඳහා ගණන් කිරීමේ අගයක් ලබා ගැනීම සඳහා ඔබට C99 අරා සාහිත්‍යය භාවිතා කළ හැකි බව මට හැඟේ, ( foo.h) විසින් නිදර්ශනය කර ඇත : #define FOO_INITIALIZER { 1, 2, 3, 4, 5 }අරාව සඳහා ආරම්භක අර්ථ දැක්වීම, අරාවේ enum { FOO_SIZE = sizeof((int [])FOO_INITIALIZER) / sizeof(((int [])FOO_INITIALIZER)[0]) };ප්‍රමාණය ලබා ගැනීම සහ extern int foo[];අරාව ප්‍රකාශ කිරීම . පැහැදිලිවම, අර්ථ දැක්වීම සාධාරණ විය යුතුය int foo[FOO_SIZE] = FOO_INITIALIZER;, නමුත් ප්‍රමාණය සැබවින්ම අර්ථ දැක්වීමට ඇතුළත් කළ යුතු නැත. මෙය ඔබට පූර්ණ සංඛ්‍යාවක් නියතයක් ලබා දෙයි FOO_SIZE.
ජොනතන් ලෙෆ්ලර්

125

externවිචල්ය තවත් පරිවර්තන ඒකකය අර්ථ දක්වා ඇත වන විචල්ය ප්රකාශයක් (ස්තුතිය නිවැරදි කිරීම සඳහා රාජරත්නම් කිරීමට) වේ. ඒ කියන්නේ විචල්‍යය සඳහා ආචයනය වෙනත් ගොනුවක වෙන් කර ඇත.

ඔබ සතුව දෙකක් කියන්න .c-files test1.cහා test2.c. ඔබ ගෝලීය විචල්ය නිර්වචනය නම් int test1_var;දී test1.cඇති අතර එවිට ඔබට මෙම විචල්ය ප්රවේශ කැමතියි test2.cඔබ භාවිතා කිරීමට ඇති extern int test1_var;දී test2.c.

සම්පූර්ණ නියැදිය:

$ cat test1.c 
int test1_var = 5;
$ cat test2.c
#include <stdio.h>

extern int test1_var;

int main(void) {
    printf("test1_var = %d\n", test1_var);
    return 0;
}
$ gcc test1.c test2.c -o test
$ ./test
test1_var = 5

21
"ව්‍යාජ අර්ථ දැක්වීම්" නොමැත. එය ප්‍රකාශයකි.
sbi

3
ඉහත නිදසුනේ, මම වෙනස් නම් extern int test1_var;කිරීමට int test1_var;, එම linker (gcc 5.4.0) තවමත් ගමන් කරයි. ඉතින්, externඇත්ත වශයෙන්ම මෙම නඩුවේ අවශ්යද?
රේඩියෝහෙඩ්

2
@radiohead: මගේ පිළිතුරෙන් , අතහැර දැමීම externබොහෝ විට ක්‍රියාත්මක වන පොදු දිගුවක් බව ඔබට පෙනී යනු ඇත - සහ විශේෂයෙන් GCC සමඟ ක්‍රියා කරයි (නමුත් GCC එයට සහය දක්වන එකම සම්පාදකයා වීමට වඩා බොහෝ සෙයින් වෙනස් ය; එය යුනික්ස් පද්ධතිවල බහුලව පවතී). - ඔබ "J.5.11" හෝ කොටසක් "නොවේ එසේ හොඳ ක්රමයක්" මගේ පිළිතුර දී (එය මම දන්නේ දැකිය හැකි වේ එය පැහැදිලි (හෝ එසේ කිරීමට උත්සාහ) ඒ අසල පෙළ දිගු).
ජොනතන් ලෙෆ්ලර්

බාහිර ප්‍රකාශයක් වෙනත් පරිවර්තන ඒකකයක නිශ්චිතවම අර්ථ දැක්විය යුතු නැත (සාමාන්‍යයෙන් නොවේ). ඇත්ත වශයෙන්ම, ප්‍රකාශනය සහ අර්ථ දැක්වීම එක හා සමාන විය හැකිය.
මතක තබා ගන්න මොනිකා

40

විචල්‍යය වෙනත් පරිවර්තන ඒකකයක වාසය කරන බව ප්‍රකාශ කිරීමට ඔබ භාවිතා කරන ප්‍රධාන පදය බාහිර ය.

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

ඔබ එය බාහිර ලෙස ප්‍රකාශ නොකරන්නේ නම් ඔබට විචල්‍ය 2 ක් ලැබෙනු ඇත.


5
වෙනත් වචන වලින් කිවහොත්, බාහිර භාවිතා කරන පරිවර්තන ඒකකය මෙම විචල්‍යය, එහි වර්ගය යනාදිය ගැන දන්නා අතර එම නිසා යටින් පවතින තර්කනයේ ප්‍රභව කේතය එය භාවිතා කිරීමට ඉඩ දෙයි, නමුත් එය විචල්‍යය වෙන් නොකරයි , වෙනත් පරිවර්තන ඒකකයක් එය කරනු ඇත. පරිවර්තන ඒකක දෙකම සාමාන්‍යයෙන් විචල්‍යය ප්‍රකාශයට පත් කරන්නේ නම්, විචල්‍යය සඳහා physical ලදායි ලෙස භෞතික ස්ථාන දෙකක් තිබිය හැකි අතර, සම්පාදනය කරන ලද කේතය තුළ සම්බන්ධිත “වැරදි” යොමු කිරීම් සහ එහි ප්‍රති ing ලයක් ලෙස සම්බන්ධකය සඳහා අපැහැදිලි වේ.
mjv

26

බාහිර විචල්‍යයක් ඔබ සම්පාදකයාට දෙන පොරොන්දුවක් ලෙස සිතීමට මම කැමතියි.

බාහිරව හමු වූ විට, සම්පාදකයාට සොයාගත හැක්කේ එහි වර්ගය මිස එය "ජීවත්වන" ස්ථානය නොවේ, එබැවින් එයට යොමු කිරීම විසඳිය නොහැක.

ඔබ එය කියන්නේ, "මාව විශ්වාස කරන්න. සම්බන්ධක වේලාවේදී මෙම සඳහන විසඳිය හැකිය."


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

18

මෙම විචල්‍යය සඳහා වන මතකය වෙනත් තැනක ප්‍රකාශයට පත් කර ඇති බව විශ්වාස කිරීමට බාහිර විසින් සම්පාදකයාට පවසයි, එබැවින් එය මතකය වෙන් කිරීමට / පරීක්ෂා කිරීමට උත්සාහ නොකරයි.

එමනිසා, ඔබට බාහිරට යොමු දැක්විය හැකි ගොනුවක් සම්පාදනය කළ හැකිය, නමුත් එම මතකය කොතැනක හෝ ප්‍රකාශ කර නොමැති නම් ඔබට සම්බන්ධ කළ නොහැක.

ගෝලීය විචල්‍යයන් සහ පුස්තකාල සඳහා ප්‍රයෝජනවත් නමුත් සම්බන්ධකය චෙක්පත ටයිප් නොකරන නිසා භයානක ය.


මතකය ප්‍රකාශ නොවේ. මෙම ප්‍රශ්නයට පිළිතුරු බලන්න: වැඩි විස්තර සඳහා stackoverflow.com/questions/1410563 .
sbi

15

ක එකතු externවෙලා ඉන්නෙ විචල්ය නිර්වචනය විචල්ය බවට ප්රකාශ . ප්‍රකාශයක් සහ අර්ථ දැක්වීමක් අතර ඇති වෙනස කුමක්දැයි මෙම නූල බලන්න .


int fooසහ extern int foo(ගොනු විෂය පථය) අතර ඇති වෙනස කුමක්ද? දෙකම ප්‍රකාශනය නේද?

14 user14284: ඒවා දෙකම ප්‍රකාශනය වන්නේ සෑම අර්ථ දැක්වීමක්ම ප්‍රකාශයක් යන අර්ථයෙන් පමණි. නමුත් මම මේ පිළිබඳ පැහැදිලි කිරීමකට සම්බන්ධ කළෙමි. ("ප්‍රකාශයක් සහ අර්ථ දැක්වීමක් අතර ඇති වෙනස කුමක්දැයි මෙම නූල බලන්න.") ඔබ සරලව සබැඳිය අනුගමනය කර කියවන්නේ නැත්තේ ඇයි?
sbi

14
                 declare | define   | initialize |
                ----------------------------------

extern int a;    yes          no           no
-------------
int a = 2019;    yes          yes          yes
-------------
int a;           yes          yes          no
-------------

ප්‍රකාශනය මඟින් මතකය වෙන් නොකරනු ඇත (මතක විබෙදුම සඳහා විචල්‍යය අර්ථ දැක්විය යුතුය) නමුත් අර්ථ දැක්වීම එසේ වනු ඇත. බාහිර පිළිතුරු පදය පිළිබඳ තවත් සරල දර්ශනයක් මෙය බැවින් අනෙක් පිළිතුරු ඇත්තෙන්ම විශිෂ්ටයි.


11

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


8

C හි ගොනුවක් තුළ විචල්‍යයක් පවසන්නේ example.c ට දේශීය විෂය පථය ලබා දී ඇති බවයි. සම්පාදකයා අපේක්ෂා කරන්නේ විචල්‍යයට එහි අර්ථ දැක්වීම එකම ගොනුව example.c තුළ තිබිය යුතු අතර එය සොයාගත නොහැකි වූ විට එය දෝෂයක් ඇති කරයි. අනෙක් අතට ශ්‍රිතයක් පෙරනිමියෙන් ගෝලීය විෂය පථයට ඇත. මේ අනුව ඔබ සම්පාදකයාට නිශ්චිතවම සඳහන් කළ යුතු නැත "බලන්න මචං ... ඔබට මෙම ශ්‍රිතයේ අර්ථ දැක්වීම මෙහි සොයාගත හැකිය". ගොනුව ඇතුළු ප්‍රකාශයක් අඩංගු ශ්‍රිතයක් සඳහා එය ප්‍රමාණවත් වේ (ඔබ ඇත්ත වශයෙන්ම ශීර්ෂ ගොනුවක් ලෙස හඳුන්වන ගොනුව). උදාහරණයක් ලෙස පහත ලිපිගොනු 2 සලකා බලන්න:
example.c

#include<stdio.h>
extern int a;
main(){
       printf("The value of a is <%d>\n",a);
}

example1.c

int a = 5;

දැන් ඔබ ගොනු දෙක එකට සම්පාදනය කරන විට, පහත දැක්වෙන විධානයන් භාවිතා කරන්න:

පියවර 1) cc -o ex example.c example1.c පියවර 2) ./ උදා

ඔබට පහත ප්‍රතිදානය ලැබේ: a හි අගය <5> වේ


8

GCC ELF ලිනක්ස් ක්‍රියාත්මක කිරීම

වෙනත් පිළිතුරු භාෂා භාවිතය පිළිබඳ දෘෂ්ටි කෝණයෙන් ආවරණය කර ඇත, එබැවින් දැන් එය ක්‍රියාත්මක කිරීමේදී එය ක්‍රියාත්මක කරන්නේ කෙසේදැයි සොයා බලමු.

main.c

#include <stdio.h>

int not_extern_int = 1;
extern int extern_int;

void main() {
    printf("%d\n", not_extern_int);
    printf("%d\n", extern_int);
}

සම්පාදනය කර විසංයෝජනය කරන්න:

gcc -c main.c
readelf -s main.o

ප්‍රතිදානයේ අඩංගු වන්නේ:

Num:    Value          Size Type    Bind   Vis      Ndx Name
 9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 not_extern_int
12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND extern_int

මෙම පද්ධතිය V ABI යාවත්කාලීන ELF පිරිවිතර "සංකේතය වගුව" පරිච්ඡේදය මඟින්:

SHN_UNDEF මෙම කොටසේ වගු දර්ශකයේ තේරුම සංකේතය නිර්වචනය කර නොමැති බවයි. සම්බන්ධක සංස්කාරකය මෙම වස්තු ගොනුව වෙනත් සංකේතයක් අර්ථ දක්වන සංකේතයක් සමඟ සංයුක්ත කරන විට, සංකේතයට මෙම ගොනුවේ යොමු කිරීම් සත්‍ය අර්ථ දැක්වීමට සම්බන්ධ වේ.

එය මූලික වශයෙන් සී ප්‍රමිතියට ලබා දෙන හැසිරීමයි extern විචල්‍යයන්ට .

මෙතැන් සිට, අවසාන වැඩසටහන සකස් කිරීම සම්බන්ධකයේ කාර්යය වන නමුත් externතොරතුරු දැනටමත් ප්‍රභව කේතයෙන් වස්තු ගොනුවට උපුටා ගෙන ඇත.

GCC 4.8 හි පරීක්ෂා කර ඇත.

සී ++ 17 පේළි විචල්‍යයන්

C ++ 17 හි, ඔබට බාහිර ඒවා වෙනුවට පේළිගත විචල්‍යයන් භාවිතා කිරීමට අවශ්‍ය විය හැකිය, මන්ද ඒවා භාවිතා කිරීම පහසුය (ශීර්ෂයට එක් වරක් පමණක් අර්ථ දැක්විය හැකිය) සහ වඩා බලවත් (ආධාරක constexpr). බලන්න: C සහ C ++ වලින් 'const static' යන්නෙන් අදහස් කරන්නේ කුමක්ද?


3
එය මගේ පහත් ඡන්දය නොවේ, එබැවින් මම නොදනිමි. කෙසේ වෙතත්, මම මතයක් ඉදිරිපත් කරමි. ප්‍රතිදානය දෙස බැලීම readelfහෝ nmප්‍රයෝජනවත් විය හැකි වුවද, ඔබ එය භාවිතා කරන්නේ කෙසේද යන්න පිළිබඳ මූලධර්ම පැහැදිලි කර externනැත, හෝ පළමු වැඩසටහන සත්‍ය අර්ථ දැක්වීම සමඟ සම්පූර්ණ කර නැත. ඔබේ කේතය පවා භාවිතා නොකරයි notExtern. නාමකරණ ගැටළුවක් ද ඇත: notExternප්‍රකාශයට පත් කරනවාට වඩා මෙහි අර්ථ දක්වා ඇතත් extern, එය පරිවර්තන ඒකකවල සුදුසු ප්‍රකාශයක් (අවශ්‍ය වනු ඇත extern int notExtern;!) තිබේ නම් එය වෙනත් ප්‍රභව ලිපිගොනු වලට ප්‍රවේශ විය හැකි බාහිර විචල්‍යයකි .
ජොනතන් ලෙෆ්ලර්

1
On ජොනතන් ලෙෆ්ලර් ප්‍රතිපෝෂණයට ස්තූතියි! සම්මත හැසිරීම සහ භාවිත නිර්දේශයන් දැනටමත් වෙනත් පිළිතුරු වලින් කර ඇති අතර, එම නිසා ක්‍රියාත්මක කිරීම මඳක් පෙන්වීමට මම තීරණය කළෙමි. භාවිතා notExternනොකිරීම කැතයි, එය සවි කළා. නාමකරණය ගැන, ඔබට වඩා හොඳ නමක් තිබේ නම් මට දන්වන්න. ඇත්ත වශයෙන්ම එය සත්‍ය වැඩසටහනක් සඳහා හොඳ නමක් නොවනු ඇත, නමුත් මම සිතන්නේ එය මෙහි ක්‍රියාකාරී භූමිකාවට හොඳින් ගැලපේ.
සිරෝ සැන්ටිලි 郝海东 郝海东 病 六四 事件 事件

නම් සම්බන්ධයෙන් ගත් කල, global_defමෙහි අර්ථ දක්වා ඇති විචල්‍යය සහ extern_refවෙනත් මොඩියුලයක අර්ථ දක්වා ඇති විචල්‍යය ගැන කුමක් කිව හැකිද? ඔවුන්ට පැහැදිලි සමමිතියක් තිබේද? ඔබ තවමත් අවසන් වී ඇත්තේ int extern_ref = 57;හෝ එය අර්ථ දක්වා ඇති ගොනුවේ එවැනි දෙයක් නිසා නම එතරම් සුදුසු නැත, නමුත් තනි ප්‍රභව ගොනුවේ සන්දර්භය තුළ එය සාධාරණ තේරීමකි. ඇති extern int global_def;වූ ශීර්ෂ දී මෙන් බොහෝ ගැටළු මතු නොවේ, එය මට පෙනේ. ඇත්ත වශයෙන්ම ඔබට සම්පූර්ණයෙන්ම.
ජොනතන් ලෙෆ්ලර්

7

ගෝලීය විචල්යයක් ලෙස හඳුනා ගැනීම සඳහා විචල්යය සමඟ බාහිර යතුරු පදය භාවිතා කරයි.

වෙනත් ගොනුවක ප්‍රකාශිත / අර්ථ දක්වා ඇති නමුත් ඕනෑම ගොනුවක බාහිර යතුරුපදය භාවිතයෙන් ප්‍රකාශිත විචල්‍යය භාවිතා කළ හැකි බව ද එය නිරූපණය කරයි.


5

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

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


5

extern සරලවම අදහස් කරන්නේ විචල්‍යයක් වෙනත් තැනක අර්ථ දක්වා ඇති බවයි (උදා: වෙනත් ගොනුවක).


4

පළමුවෙන්ම, externවිචල්යයක් නිර්වචනය කිරීම සඳහා ප්රධාන පදය භාවිතා නොවේ; ඒ වෙනුවට එය විචල්‍යයක් ප්‍රකාශ කිරීම සඳහා යොදා ගනී. මට කිව හැක්කේ externගබඩා පන්තියක් මිස දත්ත වර්ගයක් නොවේ.

externමෙම විචල්‍යය දැනටමත් කොතැනක හෝ අර්ථ දක්වා ඇති බව වෙනත් සී ගොනු හෝ බාහිර කොටස් වලට දැන ගැනීමට භාවිතා කරයි. උදාහරණය: ඔබ පුස්තකාලයක් ගොඩනඟන්නේ නම්, පුස්තකාලයේ කොතැනක හෝ අනිවාර්යයෙන්ම ගෝලීය විචල්‍යය නිර්වචනය කිරීම අවශ්‍ය නොවේ. පුස්තකාලය කෙලින්ම සම්පාදනය කරනු ඇත, නමුත් ගොනුව සම්බන්ධ කරන අතරතුර, එය අර්ථ දැක්වීම පරීක්ෂා කරයි.


3

externභාවිතා කරන බැවින් එක් first.cගොනුවකට තවත් second.cගොනුවක ගෝලීය පරාමිතියකට පූර්ණ ප්‍රවේශය ලබා ගත හැකිය .

මෙම externතුළ ප්රකාශයට පත් කළ හැකි first.cගොනු හෝ ශීර්ෂ ගොනු කිසිදු first.cඇතුළත් වේ.


3
externප්‍රකාශය විය යුත්තේ ශීර්ෂයක මිස ඇතුළත නොවන බව සලකන්න first.c, එවිට වර්ගය වෙනස් වුවහොත් ප්‍රකාශය ද වෙනස් වේ. එසේම, විචල්‍යය ප්‍රකාශ කරන ශීර්ෂකය ඇතුළත් කළ යුත්තේ second.cඅර්ථ දැක්වීම ප්‍රකාශයට අනුකූල බව සහතික කිරීම සඳහා ය. ශීර්ෂයේ ප්‍රකාශනය යනු සියල්ල එකට තබා ගන්නා මැලියම් ය; එමඟින් ලිපිගොනු වෙන වෙනම සම්පාදනය කිරීමට ඉඩ ලබා දෙන නමුත් ගෝලීය විචල්‍යයේ වර්ගය පිළිබඳ ස්ථාවර දැක්මක් ඇති බව සහතික කරයි.
ජොනතන් ලෙෆ්ලර්

2

Xc8 සමඟ එක් එක් ගොනුවේ විචල්‍යය එකම වර්ගයට සමාන ලෙස ප්‍රකාශ කිරීම ගැන ඔබ සැලකිලිමත් විය යුතුය, වැරදියට, intඑක් ගොනුවක යමක් ප්‍රකාශ කරන්න සහ achar කියන්න. මෙය විචල්‍යයන්ගේ දූෂණයට හේතු විය හැක.

මීට වසර 15 කට පමණ පෙර මයික්‍රොචිප් සංසදයකදී මෙම ගැටළුව ඉතා අලංකාර ලෙස විසඳා ඇත / * "http: www.htsoft.com" / / බලන්න "සංසදය / සියල්ල / showflat.php / Cat / 0 / අංකය / 18766 / an / 0 / page / 0 # 18766 "

නමුත් මෙම සබැඳිය තවදුරටත් ක්‍රියාත්මක නොවන බව පෙනේ ...

එබැවින් මම එය ඉක්මනින් පැහැදිලි කිරීමට උත්සාහ කරමි; global.h නමින් ගොනුවක් සාදන්න.

එහි පහත සඳහන් දේ ප්‍රකාශ කරන්න

#ifdef MAIN_C
#define GLOBAL
 /* #warning COMPILING MAIN.C */
#else
#define GLOBAL extern
#endif
GLOBAL unsigned char testing_mode; // example var used in several C files

දැන් main.c ගොනුවේ

#define MAIN_C 1
#include "global.h"
#undef MAIN_C

මෙයින් අදහස් වන්නේ main.c හි විචල්‍යය a ලෙස ප්‍රකාශයට පත් කරනු ඇති unsigned charබවයි.

දැන් global.h ඇතුළු වෙනත් ලිපිගොනු වල එය එම ගොනුව සඳහා බාහිරයක් ලෙස ප්‍රකාශයට පත් කරනු ඇත .

extern unsigned char testing_mode;

නමුත් එය නිවැරදිව ප්‍රකාශයට පත් කරනු ඇත unsigned char.

පැරණි සංසද පෝස්ට් මෙය තරමක් පැහැදිලිව පැහැදිලි කර ඇත. gotchaඑක් ගොනුවක විචල්‍යයක් ප්‍රකාශ කිරීමට ඉඩ දී එය වෙනත් ආකාරයකින් වෙනත් වර්ගයක් ලෙස ප්‍රකාශ කිරීමට ඉඩ සලසන සම්පාදකයක් භාවිතා කරන විට මෙය සැබෑ විභවයකි. ඒ හා සම්බන්ධ ගැටලු නම්, ඔබ වෙනත් ගොනුවක int_ ලෙස ප්‍රකාශිත ටෙස්ටිං_මෝඩ් යැයි පැවසුවහොත් එය එය බිට් 16 var යැයි සිතන අතර රැම්හි තවත් කොටසක් නැවත ලිවීමෙන් වෙනත් විචල්‍යයක් දූෂිත විය හැකිය. නිදොස් කිරීම දුෂ්කර!


0

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

මම මෙම රටාව බහු ගොනු හරහා භාවිතා කරමි. එබැවින් හැකි තරම් ස්වයං අන්තර්ගතයන් තබා ගැනීම සඳහා, මම සෑම ශීර්ෂයකම තනි ගෝලීය සාර්ව නැවත භාවිතා කරමි. මගේ ශීර්ෂකය මේ වගේ ය:

//file foo_globals.h
#pragma once  
#include "foo.h"  //contains definition of foo

#ifdef GLOBAL  
#undef GLOBAL  
#endif  

#ifdef GLOBAL_FOO_IMPLEMENTATION  
#define GLOBAL  
#else  
#define GLOBAL extern  
#endif  

GLOBAL Foo foo1;  
GLOBAL Foo foo2;


//file main.cpp
#define GLOBAL_FOO_IMPLEMENTATION
#include "foo_globals.h"

//file uses_extern_foo.cpp
#include "foo_globals.h
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.