인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

inflearn님의 프로필 이미지
inflearn

작성한 질문수

홍정모의 따라하며 배우는 C언어

12.8 정적 변수의 외부 연결 external linkage

gcc는 extrenal linkage init 할 때 문제가 발생합니다

작성

·

201

1

18:02
 
VS2019에선 문제가 없어 보이지만
gcc 6.3.0 기준 warning 발생합니다
경고문:
warning: 'g_int' initialized and declared 'extern'
 
근데 또 찾아보니
IBM 컴파일러에선 문제가 없는 것 같습니다.
컴파일러마다 문법이 다른 듯하니 웬만하면 안 쓰는 게 좋을 것 같습니다.

답변 2

2

아하,

코드를 보니 12_8_extern_init_2.c (main함수가 없는 부분)에 

777로 초기화하신 것 같네요.

 

12_8_extern_init.c에서 초기화한 뒤에 12_8_extern_init_2.c로 끌어다 써야 하는 것이 맞습니다.

 

extern g_int는 외부에 선언된 g_int를 끌어다 쓰겠다는 의미입니다.

변수를 위해 메모리를 따로 할당하겠다는 말이 아니지요.

 

이를 main 함수가 없는 파일에 초기화하면 당연히 multiple definition 에러가 뜹니다.

아래와 같이요.

minchul@minchul:~/workspace/DBC-QnA/src$ gcc -o test 12_8_extern_init.c 12_8_extern_init_2.c
12_8_extern_init_2.c:3:12: warning: ‘g_int’ initialized and declared ‘extern’
    3 | extern int g_int = 777; // Warning or Error!!
      |            ^~~~~
/usr/bin/ld: /tmp/ccMHNtnJ.o:(.data+0x0): multiple definition of `g_int'; /tmp/ccU9Sjja.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

 

그래서  main 함수가 있는 12_8_extern_init에서  g_int를 초기화하고

12_8_extern_init_2.c에서 이를 extern으로 (초기화하는 것이 아닌) 끌어다 써야 합니다.

 

아래 코드를 작성하고 실행해보세요.

12_8_extern_init.c

// 초기화한다
int g_int = 777;

void testFunc();

int main() {
    testFunc();

    return 0;
}

12_8_extern_init_2.c

#include <stdio.h>

// 끌어다 쓴다
extern int g_int;

void testFunc() {
    printf("g_int == 777 == %d\n", g_int);
}

 

올바르게 실행된 예시는 다음과 같습니다.

minchul@minchul:~/workspace/DBC-QnA/src$ gcc -o test 12_8_extern_init.c 12_8_extern_init_2.c
minchul@minchul:~/workspace/DBC-QnA/src$ ./test
g_int == 777 == 777

 

inflearn님의 프로필 이미지
inflearn
질문자

우선 답변 감사드립니다.

 

안타깝게도 제 질문은 그것이 아니었습니다.

해당 강의(12.8강)의 18:21 부분부터 시작되는 문제를 말씀드린 것이었습니다.

 

Translation Unit 외의 부분에서 extren 키워드와 함께 정의(혹은 선언 및 할당)

즉, 일종의 초기화를 한다면 경고와 오류를 발생시키지만,

MSVC 2019와 IBM 컴파일러에선 문제가 안 되는 것 같아

혹시 제가 무언가를 놓치고 있는 건지, 그게 아니라면

이 내용은 수정을 하는 것이 어떤지 등의 의견을 구하고자 하는 것이었습니다.

 

오늘 제가 직접 2019는 아니지만 MSVC 2022 Community에서 빌드 후 실행해보니

워닝조차 뜨지 않고 정상 작동 하더군요.

 

상당히 복잡한 문제인 것 같습니다.

이해했습니다.

extern 변수의 초기화는 말씀하신대로 컴파일러마다 차이가 있는 것으로 보이네요.

gcc는 (extern 본연의 의미답게) 외부의 변수를 참조하는 형태로만 사용하길 권하는 것으로 보입니다.

추후 개발을 하실 적에도 extern 변수를 초기화 하고 외부 linked된 변수를 정의만 하기보다는

변수를 초기화하고, extern 변수로 끌어다 사용하는 방향으로 개발하시길 권합니다.

감사합니다.

inflearn님의 프로필 이미지
inflearn
질문자

👍

1

extern은 gcc 컴파일러로도 자주 사용됩니다.

혹시 두 소스를 빌드할 때 어떻게 빌드하셨나요?

inflearn님의 프로필 이미지
inflearn
질문자

gcc와 gcc-11 및 clang으로 mac 12.1 Monterey에서 빌드하였습니다.

깃허브 올리는 게 빠를 것 같아 첨부합니다.

https://github.com/YI-Hongju/DBC-QnA

inflearn님의 프로필 이미지
inflearn

작성한 질문수

질문하기