C에서는 extern
함수 선언 전에 사용 된 키워드의 영향을 느끼지 못했습니다 . 처음에는 정의 할 때 생각 extern int f();
단일 파일에 힘 이 외부 파일의 범위를 구현 할 수 있습니다. 그러나 나는 두 가지를 발견했다.
extern int f();
int f() {return 0;}
과
extern int f() {return 0;}
gcc의 경고없이 잘 컴파일하십시오. 나는 사용했다 gcc -Wall -ansi
; 심지어 //
의견을 받아들이지 않을 것 입니다.
extern
이전 함수 정의 를 사용하는 데 영향이 있습니까? 또는 기능에 대한 부작용이없는 선택적인 키워드 일뿐입니다.
후자의 경우 표준 디자이너가 왜 불필요한 키워드로 문법을 버리려고했는지 이해가 가지 않습니다.
편집 : 내가 사용이 거기 알고, 명확히하기 위해 extern
변수,하지만 난 단지에 대해 부탁 해요 extern
에서 기능 .
답변
foo.c와 bar.c라는 두 파일이 있습니다.
여기 foo.c가 있습니다
#include <stdio.h>
volatile unsigned int stop_now = 0;
extern void bar_function(void);
int main(void)
{
while (1) {
bar_function();
stop_now = 1;
}
return 0;
}
자, 여기 bar.c입니다
#include <stdio.h>
extern volatile unsigned int stop_now;
void bar_function(void)
{
while (! stop_now) {
printf("Hello, world!\n");
sleep(30);
}
}
보시다시피 foo.c와 bar.c 사이에 공유 헤더가 없지만 bar.c는 foo.c에 연결될 때 선언 된 것이 필요하고 foo.c는 bar.c에 연결될 때 함수가 필요합니다.
‘extern’을 사용하면 컴파일러가 링크 타임에 다음과 같은 것이 발견 될 때 (정적이 아님) 알 수 있습니다. 현재 패스에서 나중에 예약 할 예정이므로 예약하지 마십시오. 함수와 변수는 이와 관련하여 동일하게 취급됩니다.
모듈간에 전역을 공유해야하고 헤더에 넣거나 초기화하지 않으려는 경우 매우 유용합니다.
기술적으로 라이브러리 공개 헤더의 모든 함수는 ‘extern’이지만 레이블을 지정하면 컴파일러에 따라 거의 이점이 없습니다. 대부분의 컴파일러는 스스로 알아낼 수 있습니다. 보시다시피 이러한 함수는 실제로 다른 곳에 정의되어 있습니다.
위의 예에서 main ()은 hello world를 한 번만 인쇄하지만 bar_function ()을 계속 입력합니다. 또한이 예제에서는 bar_function ()이 반환되지 않습니다 (단순한 예제이므로). 신호가 충분히 실용적이지 않으면 신호가 서비스 될 때 stop_now가 수정된다고 상상하십시오.
Externs는 신호 처리기, 헤더 또는 구조에 넣기를 원하지 않는 뮤텍스 등과 같은 것들에 매우 유용합니다. 대부분의 컴파일러는 외부 객체를 위해 메모리를 예약하지 않도록 최적화합니다. 객체가 정의 된 모듈에서 예약 할 것입니다. 그러나 공용 함수를 프로토 타이핑 할 때 최신 컴파일러로이를 지정하는 데는 별다른 의미가 없습니다.
희망이 있습니다 🙂
답변
표준을 기억하는 한 모든 함수 선언은 기본적으로 “extern”으로 간주되므로 명시 적으로 지정할 필요가 없습니다.
이 키워드는 변수와 함께 사용할 수 있기 때문에 쓸모가 없습니다 (이 경우 링크 문제를 해결하는 유일한 솔루션입니다). 그러나 기능을 사용하면 옵션입니다.
답변
함수 정의와 기호 선언이라는 두 가지 개별 개념을 구별해야합니다. “extern”은 링키지 수정 자이며, 나중에 참조되는 심볼이 정의 된 위치에 대한 컴파일러의 힌트입니다 (힌트는 “여기서는 안됩니다”).
내가 쓰면
extern int i;
C 파일의 파일 범위 (함수 블록 외부)에서 “변수가 다른 곳에서 정의 될 수 있습니다”라고 말합니다.
extern int f() {return 0;}
함수 f의 선언과 함수 f의 정의입니다. 이 경우 정의는 extern을 대체합니다.
extern int f();
int f() {return 0;}
먼저 선언 다음에 정의가옵니다.
extern
파일 범위 변수를 선언하고 동시에 정의하려는 경우 사용 이 잘못되었습니다. 예를 들어
extern int i = 4;
컴파일러에 따라 오류 또는 경고가 표시됩니다.
extern
변수의 정의를 명시 적으로 피하려는 경우 사용법 이 유용합니다.
설명하겠습니다 :
ac 파일에 다음이 포함되어 있다고 가정 해 봅시다.
#include "a.h"
int i = 2;
int f() { i++; return i;}
파일 ah는 다음을 포함합니다 :
extern int i;
int f(void);
bc 파일에는 다음이 포함됩니다.
#include <stdio.h>
#include "a.h"
int main(void){
printf("%d\n", f());
return 0;
}
헤더의 extern은 링크 단계에서 컴파일러에게 “정의가 아니라 선언”이라고 알려주기 때문에 유용합니다. i를 정의하고 공간을 할당하고 값을 할당하는 ac 행을 제거하면 프로그램이 정의되지 않은 참조로 컴파일하지 않아야합니다. 이것은 개발자에게 변수를 참조했지만 아직 정의하지 않았다고 알려줍니다. 반면에 “extern”키워드를 생략하고 int i = 2
행을 제거 하면 프로그램이 여전히 컴파일됩니다. 기본값은 0으로 정의됩니다.
파일 범위 변수는 함수 상단에 선언하는 블록 범위 변수와 달리 명시 적으로 값을 지정하지 않으면 기본값 0 또는 NULL로 암시 적으로 정의됩니다. extern 키워드는 이러한 암시 적 정의를 피하므로 실수를 피할 수 있습니다.
함수의 경우 함수 선언에서 키워드는 실제로 중복됩니다. 함수 선언에는 암시 적 정의가 없습니다.
답변
extern
키워드는 환경에 따라 다른 형태를 취한다. 선언을 사용할 수있는 경우 extern
키워드는 번역 단위에서 앞서 지정한 연결을 사용합니다. 그러한 선언이 없으면 extern
외부 연결을 지정합니다.
static int g();
extern int g(); /* g has internal linkage */
extern int j(); /* j has tentative external linkage */
extern int h();
static int h(); /* error */
다음은 C99 초안 (n1256)의 관련 단락입니다.
6.2.2 식별자의 연결
[…]
4 해당 식별자의 사전 선언이 보이는 범위에서 스토리지 등급 지정자 extern으로 선언 된 식별자 사전 선언에 지정된 연결로. 사전 선언이 표시되지 않거나 사전 선언이 연결을 지정하지 않으면 식별자에 외부 연결이 있습니다.
5 함수에 대한 식별자 선언에 스토리지 클래스 지정자가 없으면 해당 링크는 스토리지 클래스 지정자 extern으로 선언 된 것처럼 정확하게 결정됩니다. 오브젝트의 식별자 선언에 파일 범위가 있고 스토리지 클래스 지정자가없는 경우 링크는 외부입니다.
답변
인라인 함수에는 의미 에 대한 특별한 규칙 이 있습니다 extern
. (인라인 함수는 C99 또는 GNU 확장이며 원래 C에는 없었습니다.
인라인이 아닌 기능의 경우 extern
기본적으로 켜져 있으므로 필요하지 않습니다.
C ++의 규칙은 다릅니다. 예를 들어, extern "C"
C ++에서 호출 할 C 함수의 C ++ 선언에 필요하며에 대해 다른 규칙이 inline
있습니다.
답변
IOW, extern은 중복 적이며 아무것도하지 않습니다.
이것이 10 년 후의 이유입니다.
- Coccinelle 과 같은 코드 변환 도구 는 제거를 위해 함수 선언 에 플래그
extern
를 지정 하는 경향이 있습니다 . - 이와 같은 코드베이스
git/git
는 결론을 따르고extern
코드에서 제거합니다 (Git 2.22, Q2 2019).
참조 ad6dad0 커밋 , b199d71 커밋 , 5,545,442 커밋 에 의해 (2019년 4월 29일) 덴튼 리우 ( Denton-L
) .
(가 합병 – Junio C 하마노 gitster
– 에 4aeeef3 커밋 2019 13 월)
*.[ch]
:를extern
사용하여 함수 선언에서 제거spatch
extern
함수 선언에서 제거하도록 푸시되었습니다 .
extern
Coccinelle에서 잡은 함수 선언에 대해 ” ” 의 일부 인스턴스를 제거하십시오 .
Coccinelle은__attribute__
varargs를 사용하여 함수를 처리하는 데 약간의 어려움이 있으므로 일부extern
패치는 향후 패치에서 처리되도록 남겨 두었습니다.이것은 사용 된 Coccinelle 패치입니다.
@@ type T; identifier f; @@ - extern T f(...);
그리고 그것은 다음과 같이 실행되었습니다 :
$ git ls-files \*.{c,h} | grep -v ^compat/ | xargs spatch --sp-file contrib/coccinelle/noextern.cocci --in-place
그러나 이것이 항상 간단한 것은 아닙니다.
Denton Liu ( )의 commit 7027f50 (2019 년 9 월 04 일)을 참조하십시오 . (가 합병 – 덴튼 리우 – 에 7027f50 커밋 2019 05 구월)Denton-L
Denton-L
compat/*.[ch]
:extern
spatch를 사용하여 함수 선언에서 제거5545442 (
*.[ch]
:extern
spatch, 2019-04-29, Git v2.22.0-rc0을 사용하여 함수 선언에서 제거)에서 우리는를 사용하여 함수 선언에서 externs를 제거spatch
했지만compat/
일부는 업스트림에서 직접 복사되므로 파일을 의도적으로 제외했습니다. 향후 업데이트를 수동으로 병합하는 것이 더 간단 해집니다.마지막 커밋에서는 업스트림에서 가져온 파일을 확인하여 파일을 제외하고
spatch
나머지 파일에서 실행할 수 있습니다 .이것은 사용 된 Coccinelle 패치입니다.
@@ type T; identifier f; @@ - extern T f(...);
그리고 그것은 다음과 같이 실행되었습니다 :
$ git ls-files compat/\*\*.{c,h} | xargs spatch --sp-file contrib/coccinelle/noextern.cocci --in-place $ git checkout -- \ compat/regex/ \ compat/inet_ntop.c \ compat/inet_pton.c \ compat/nedmalloc/ \ compat/obstack.{c,h} \ compat/poll/
Coccinelle은
__attribute__
varargs를 처리하는 데 문제가 있으므로 나머지 변경 사항이 남아 있지 않도록 다음을 실행했습니다.$ git ls-files compat/\*\*.{c,h} | xargs sed -i'' -e 's/^\(\s*\)extern \([^(]*([^*]\)/\1\2/' $ git checkout -- \ compat/regex/ \ compat/inet_ntop.c \ compat/inet_pton.c \ compat/nedmalloc/ \ compat/obstack.{c,h} \ compat/poll/
Git 2.24 (2019 년 4 분기)에서는 스퓨리어스 extern
가 제거됩니다.
Emily Shaffer ( )의 commit 65904b8 (2019 년 9 월 30 일)을 참조하십시오 .
도움 : Jeff King ( ) . Denton Liu ( )의 commit 8464f94 (2019 년 9 월 21 일)를
참조하십시오 .
도움 : Jeff King ( ) . (가 합병 – Junio C 하마노 – 에 59b19bc 커밋 2019 07 10 월)nasamuffin
peff
Denton-L
peff
gitster
promisor-remote.h
:extern
함수 선언에서 삭제이 파일을 작성하는 동안 새로운 함수 선언이 도입 될 때마다
extern
.
그러나 5545442 (*.[ch]
: 2019-04-29, Git v2.22.0-rc0을extern
사용하여 함수 선언에서 제거) 부터 시작 하여spatch
externs가 불필요하기 때문에 함수 선언에 사용되지 않도록 적극적으로 노력하고 있습니다.이 스퓨리어스를 제거하십시오
extern
.
답변
extern
키워드 알리는 함수 나 변수가 외부 링크 가지고있는 컴파일러 – 그것이 정의 된 것 이외의 파일에서 보이는 것을, 다른 말로한다. 이런 의미에서 static
키워드 와 반대의 의미를 갖습니다 . extern
다른 파일에는 정의가 표시되지 않거나 여러 정의가 발생하기 때문에 정의 시점에 배치하는 것이 약간 이상합니다 . 일반적으로 extern
외부 가시성 (예 : 헤더 파일)이있는 선언을 넣고 다른 곳에 정의를 넣습니다.