C에서 extern 키워드를 올바르게 사용하는 방법


235

내 질문은 함수가 externC 의 키워드 로 참조되어야 할 때에 관한 것 입니다.

이것이 언제 실제로 사용되어야하는지 알지 못합니다. 프로그램을 작성할 때 사용하는 모든 기능을 포함 된 헤더 파일을 통해 사용할 수 있습니다. 그렇다면 extern헤더 파일에 노출되지 않은 항목에 액세스하는 것이 유용한 이유는 무엇입니까?

나는 어떻게 extern잘못 작동 하는지 생각할 수 있습니다 . 그렇다면 수정하십시오.

편집 :extern 헤더 파일에 키워드가없는 기본 선언 인 경우 뭔가 해야합니까 ?


답변:


290

" extern"는 연결을 변경합니다. 키워드를 사용하면 함수 / 변수가 다른 곳에서 사용 가능한 것으로 가정하고 해결이 링커로 지연됩니다.

함수와 변수에 대한 "extern"의 차이점이 있습니다. 변수에 대해서는 변수 자체를 인스턴스화하지 않습니다. 즉, 메모리를 할당하지 않습니다. 다른 곳에서 수행해야합니다. 따라서 다른 곳에서 변수를 가져 오려면 중요합니다. 함수의 경우, 이는 컴파일러에게 연결이 extern임을 알려줍니다. 이것이 기본값이므로 (키워드 "static"을 사용하여 함수가 extern linkage를 사용하여 바인딩되지 않았 음을 나타 내기 때문에) 명시 적으로 사용할 필요는 없습니다.


1
왜 같은 통근 일이 망할 놈에있다 : 매우 인기있는 현대적인 소프트웨어는 그것을 확인 : github.com/git/git/blob/master/strbuf.h
rsjethani

K & R은 기본적으로 함수를 "extern"으로 선언하는 것이 중요하지 않지만이 답변은 혼란을 해결합니다!
acgtyrant

@rsjethani 나는 문서를보다 엄격하고 형식적으로 만드는 것이라고 생각합니다.
acgtyrant

어리석은 질문 일지 모르지만 이것이 앞으로 선언과 어떻게 비교됩니까?
weberc2

196

extern 은이 데이터가 어딘가에 정의되어 있으며 링커와 연결될 것이라고 컴파일러에 알려줍니다.

여기에있는 답변의 도움으로 몇 명의 친구들과 이야기하는 것은 extern을 사용하는 실제적인 예입니다 .

예 1- 함정을 보여 주려면

File stdio.h:

int errno;
/* other stuff...*/

myCFile1.c:
#include <stdio.h>

Code...

myCFile2.c:
#include <stdio.h>

Code...

myCFile1.o 및 myCFile2.o가 링크 된 경우 각 c 파일에는 별도의 errno 사본이 있습니다. 링크 된 모든 파일에서 동일한 errno 를 사용할 수 있으므로 문제가됩니다 .

예 2- 수정 사항.

File stdio.h:

extern int errno;
/* other stuff...*/

File stdio.c

int errno;

myCFile1.c:
#include <stdio.h>

Code...

myCFile2.c:
#include <stdio.h>

Code...

이제 myCFile1.o와 MyCFile2.o가 모두 링커에 의해 연결되어 있으면 둘 다 동일한 errno를 가리 킵니다 . 따라서 extern으로 구현을 해결하십시오 .


70
문제는 myCFile1과 myCFile2 모듈에 별도의 errno 사본이 있다는 것이 아니라 "errno"라는 심볼을 노출한다는 것입니다. 링커에서이를 확인할 때 어떤 "errno"를 선택해야하는지 알 수 없으므로 오류 메시지와 함께 구제됩니다.
cwick

2
"링커에 의해 연결됨"은 실제로 무엇을 의미합니까?
모두이

7
@MarcelFalliere Wiki ~ 컴파일러는 각 소스 파일을 자체적으로 컴파일하고 각 소스 파일에 대한 객체 파일을 만듭니다. 링커는 이러한 객체 파일을 1 개의 실행 파일에 연결합니다.
Bitterblue

1
@cwick GCC는 오류를 제공 또는 사용 후에도 경고하지 않습니다 -Wall-pedantic. 왜 ? 그리고 어떻게 ?
b-ak

6
포함 가드가이 정확한 것을 보호하지 않습니까?
obskyr

32

이미 extern키워드가 기능에 중복 되는 것으로 언급되었습니다 .

컴파일 단위에서 공유되는 변수의 경우 extern 키워드를 사용하여 헤더 파일로 변수를 선언 한 다음 extern 키워드없이 단일 소스 파일로 정의해야합니다. 모범 사례를 위해 단일 소스 파일은 헤더 파일 이름을 공유하는 것이어야합니다.


@aib "기능 중복", bluebrother의 답변에서 내 의견을 확인하십시오.
rsjethani

헤더 파일에 함수를 노출시키지 않으려면 어떻게해야합니까? 한 C 파일에서 변수를 선언하고 다른 C 파일에서 extern으로 변수에 액세스하는 것이 좋지 않을 것입니다. 링커에서 문제를 해결하고 나머지 헤더를 숨기십시오.
ste3e

16

몇 년 후, 나는이 질문을 발견했다. 모든 답변과 의견을 읽은 후 몇 가지 세부 사항을 명확히 할 수 있다고 생각했습니다. 이는 Google 검색을 통해 여기에 온 사람들에게 유용 할 수 있습니다.

문제는 "extern"함수 사용에 관한 것이므로 전역 변수와 함께 "extern"사용을 무시합니다.

3 가지 함수 프로토 타입을 정의 해 봅시다 :

//--------------------------------------
//Filename: "my_project.H"
extern int function_1(void);
static int function_2(void);
       int function_3(void);

헤더 파일은 다음과 같이 기본 소스 코드에서 사용할 수 있습니다.

//--------------------------------------
//Filename: "my_project.C"
#include "my_project.H"

void main(void){
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 1234;

컴파일하고 링크하기 위해서는 해당 함수를 호출하는 동일한 소스 코드 파일에서 "function_2"를 정의해야합니다. 다른 두 함수는 서로 다른 소스 코드 " .C" 로 정의 되거나 소스 코드 가없는 바이너리 파일 ( .OBJ, * .LIB, * .DLL)에있을 수 있습니다.

차이점을 더 잘 이해하기 위해 다른 "* .C"파일에 "my_project.H"헤더를 다시 포함시켜 보겠습니다. 동일한 프로젝트에서 다음 파일을 추가합니다.

//--------------------------------------
//Filename: "my_big_project_splitted.C"
#include "my_project.H"

void old_main_test(void){
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 5678;

int function_1(void) return 12;
int function_3(void) return 34;

주목해야 할 중요한 기능 :

  • 함수가 헤더 파일에서 "정적"으로 정의되면 컴파일러 / 링커는 해당 포함 파일을 사용하는 각 모듈에서 해당 이름의 함수 인스턴스를 찾아야합니다.

  • C 라이브러리의 일부인 함수는 프로토 타입을 해당 모듈에서만 "정적"으로 재정 의하여 하나의 모듈에서만 대체 할 수 있습니다. 예를 들어, "malloc"및 "free"호출을 대체하여 메모리 누수 감지 기능을 추가하십시오.

  • 함수 "extern"지정자는 실제로 필요하지 않습니다. "정적"을 찾을 수 없으면 함수는 항상 "extern"인 것으로 가정합니다.

  • 그러나 "extern"은 변수의 기본값이 아닙니다. 일반적으로 많은 모듈에서 볼 수있는 변수를 정의하는 헤더 파일은 "extern"을 사용해야합니다. 헤더 파일이 하나의 모듈에서만 포함되는 것이 유일한 예외입니다.

    많은 프로젝트 관리자는 이러한 변수를 헤더 파일이 아닌 모듈의 시작 부분에 배치해야합니다. 비디오 게임 에뮬레이터 "Mame"과 같은 일부 대규모 프로젝트에서는 이러한 변수가 해당 변수를 사용하는 첫 번째 함수 위에 만 나타나도록 요구하기도합니다.


그렇다면 왜 정적 함수에 정의와 외부 함수가 필요합니까? (이것이 2 년 늦었다는 것을 알고 있지만 이것은 실제로 이해하는 데 실제로 도움이됩니다)
SubLock69

2
100 행에서 함수를 호출하고 500 행에서 함수를 정의하면 정의가 필요합니다. 100 행은 정의되지 않은 프로토 타입을 선언합니다. 따라서 상단 근처에 프로토 타입을 추가합니다.
Christian Gingras

15

C에서는 프로토 타입이 다른 곳에 정의 된 함수를 선언하기 때문에 함수 프로토 타입에는 'extern'이 내포되어 있습니다. 다시 말해 함수 프로토 타입에는 기본적으로 외부 연결이 있습니다. 'extern'을 사용하는 것은 좋지만 중복됩니다.

정적 링크가 필요한 경우 함수는 프로토 타입과 함수 헤더 모두에서 '정적'으로 선언되어야하며 일반적으로 모두 동일한 .c 파일에 있어야합니다.


8

extern키워드와 관련하여 다음과 같은 좋은 기사가 나와 있습니다. http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

extern함수 선언에서 사용 하는 것이 중복 된다는 것에 동의하지는 않지만 . 이것은 컴파일러 설정으로되어 있습니다. 따라서 extern필요할 때 함수 선언에서를 사용하는 것이 좋습니다 .


3
여기에 오기 전에 geeksforgeeks.org 기사를 읽었지만 글을 잘 작성하지 못했습니다. 문법 및 구문의 단점 외에도 많은 단어를 사용하여 동일한 포인트를 여러 번 만든 다음 중요한 정보를 생략합니다. 예를 들어, 예 4에서 갑자기 'somefile.h'가 포함되었지만 "somefile.h에 var 정의가 있다고 가정"외에는 아무 것도 언급되지 않았습니다. 우리가 "추천하고있는"정보는 내가 찾고있는 정보 일뿐입니다. 불행히도,이 페이지의 답변이 훨씬 더 좋습니다.
엘리스 반 루이

6

프로그램의 각 파일이 먼저 객체 파일로 컴파일 된 경우 객체 파일이 서로 연결되어 있어야합니다 extern. "이 함수는 존재하지만 그 코드는 다른 곳에 있습니다. 당황하지 마십시오."


음, 그것이 번역이 정상적으로 수행되는 방식입니다. 소스 파일은 객체 파일로 컴파일 된 다음 링크됩니다. 이 경우 언제 extern이 필요하지 않습니까? #include를 사용하여 함수를 얻는 것이 아니라 함수 프로토 타입을 사용하지도 않습니다. 나는 당신이 무슨 말을하는지 이해하지 못합니다.
David Thornley

요즘 물건을 잘못 읽음 으로써이 문제가있는 것 같습니다. 미안합니다. C를 처음 사용했을 때는 한 파일의 함수를 다른 파일에 직접 포함시키기 위해 #include "file.c"를 사용했습니다. 그런 다음 'extern'을 사용하는 방법을 알아 냈습니다. 나는 그가 저와 같은 실수를하고 있다고 생각했습니다.
Chris Lutz

4

헤더 파일의 모든 함수 및 변수 선언은이어야합니다 extern.

이 규칙에 대한 예외는 헤더에 정의 된 인라인 함수와 헤더에 정의되어 있지만 변수가 변환 단위 (헤더가 포함 된 소스 파일)에 로컬이어야하는 변수입니다 static.

소스 파일에서 파일에 extern정의 된 함수 및 변수에 사용해서는 안됩니다. 로컬 정의 앞에 접두사를 지정 static하고 공유 정의에 대해서는 아무 것도 수행하지 않습니다. 기본적으로 외부 심볼이됩니다.

extern소스 파일에서 사용하는 유일한 이유 는 다른 소스 파일에 정의되어 있고 헤더 파일이 제공되지 않은 함수 및 변수를 선언하기위한 것입니다.


함수 프로토 타입 선언 extern은 실제로 불필요합니다. 일부 사람들은 공간을 낭비하고 함수 선언은 이미 라인 한계를 초과하는 경향이 있기 때문에 싫어합니다. 다른 방법으로는 함수와 변수를 같은 방식으로 처리 할 수 ​​있기 때문에 좋아합니다.


"헤더 파일의 모든 함수 및 변수 선언이 extern이어야하는 이유"를 설명 할 수 있습니까? 다른 응답에서 기본적으로 extern이라는 것을 알 수 있습니다.
lillq

@Lane : extern함수 선언의 경우 선택 사항이지만 변수와 함수를 같은 방식으로 처리하는 것을 좋아합니다. 적어도 내가 왜 이것을 시작했는지 정확히 기억하지 못하기 때문에 이것이 가장 합리적인 방법입니다.)
Christoph

전역 변수를 항상 C 파일에 포함 시켜서 헤더를 포함하는 다른 임의의 C 파일에 표시되지 않는 것이 좋습니다. 그리고 명확성을 위해 초기화 된 실제 싱크를 제외한 모든 전역에서 항상 extern을 사용합니다. 접두사가 extern이면 다른 곳에서 정의됩니다.
ste3e

3

다른 소스 파일에 실제로 정의 된 함수 는 헤더 에만 선언 해야합니다 . 이 경우 헤더에서 프로토 타입을 선언 할 때 extern 을 사용해야합니다 .

대부분의 경우 함수는 다음 중 하나입니다 (모범 사례와 유사).

  • 정적 (.c 파일 외부에는 보이지 않는 일반 함수)
  • 정적 인라인 (.c 또는 .h 파일의 인라인)
  • extern (다음 종류의 헤더에서 선언 (아래 참조))
  • [키워드 없음] (extern 선언을 사용하여 액세스 할 수있는 일반 함수)

이것이 기본 인 경우 프로토 타입을 선언 할 때 왜 extern입니까?
lillq 2018 년

@Lane : 약간 편향 될 수 있지만, 내가 작업 한 모든 제정신 프로젝트는 다음 규칙을 사용합니다. 헤더에서 외부 함수 (따라서 extern)에 대해서만 프로토 타입을 선언하십시오. .c 파일에서 일반 프로토 타입을 사용하여 특정 순서를 지정할 필요가 없지만 헤더에 배치해서는 안됩니다.
에두아르-가브리엘 문테 아누

1

다른 dll 또는 lib에 해당 함수가 정의되어 있으면 컴파일러가 링커를 찾아 해당 함수를 찾습니다. 일반적인 경우는 OS API에서 함수를 호출 할 때입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.