IT박스

extern 키워드가 C 함수에 미치는 영향

itboxs 2020. 6. 2. 19:04
반응형

extern 키워드가 C 함수에 미치는 영향


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가 수정되는 것을 상상해보십시오.

Extern은 신호 처리기, 헤더 또는 구조에 넣기를 원하지 않는 뮤텍스 등과 같은 것들에 매우 유용합니다. 대부분의 컴파일러는 외부 객체에 대한 메모리를 예약하지 않도록 최적화합니다. 객체가 정의 된 모듈에서 예약 할 것입니다. 그러나 공용 함수를 프로토 타이핑 할 때 최신 컴파일러로이를 지정하는 데는 별다른 의미가 없습니다.

희망이 있습니다 :)


표준을 기억하는 한 모든 함수 선언은 기본적으로 "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변수의 정의를 명시 적으로 피하려는 경우 사용법 이 유용합니다.

Let me explain:

Let's say the file a.c contains:

#include "a.h"

int i = 2;

int f() { i++; return i;}

The file a.h includes:

extern int i;
int f(void);

and the file b.c contains:

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

int main(void){
    printf("%d\n", f());
    return 0;
}

The extern in the header is useful, because it tells the compiler during the link phase, "this is a declaration, and not a definition". If I remove the line in a.c which defines i, allocates space for it and assigns a value to it, the program should fail to compile with an undefined reference. This tells the developer that he has referred to a variable, but hasn't yet defined it. If on the other hand, I omit the "extern" keyword, and remove the int i = 2 line, the program still compiles - i will be defined with a default value of 0.

File scope variables are implicitly defined with a default value of 0 or NULL if you do not explicitly assign a value to them - unlike block-scope variables that you declare at the top of a function. The extern keyword avoids this implicit definition, and thus helps avoid mistakes.

For functions, in function declarations, the keyword is indeed redundant. Function declarations do not have an implicit definition.


The extern keyword takes on different forms depending on the environment. If a declaration is available, the extern keyword takes the linkage as that specified earlier in the translation unit. In the absence of any such declaration, extern specifies external linkage.

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 */

Here are the relevant paragraphs from the C99 draft (n1256):

6.2.2 Linkages of identifiers

[...]

4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,23) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

5 If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.


Inline functions have special rules about what extern means. (Note that inline functions are a C99 or GNU extension; they weren't in original C.

For non-inline functions, extern is not needed as it is on by default.

Note that the rules for C++ are different. For example, extern "C" is needed on the C++ declaration of C functions that you are going to call from C++, and there are different rules about inline.


The extern keyword informs the compiler that the function or variable has external linkage - in other words, that it is visible from files other than the one in which it is defined. In this sense it has the opposite meaning to the static keyword. It is a bit weird to put extern at the time of the definition, since no other files would have visibility of the definition (or it would result in multiple definitions). Normally you put extern in a declaration at some point with external visibility (such as a header file) and put the definition elsewhere.


IOW, extern is redundant, and does nothing.

That is why, 10 years later:

See commit ad6dad0, commit b199d71, commit 5545442 (29 Apr 2019) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit 4aeeef3, 13 May 2019)

*.[ch]: remove extern from function declarations using spatch

There has been a push to remove extern from function declarations.

Remove some instances of "extern" for function declarations which are caught by Coccinelle.
Note that Coccinelle has some difficulty with processing functions with __attribute__ or varargs so some extern declarations are left behind to be dealt with in a future patch.

This was the Coccinelle patch used:

  @@
    type T;
    identifier f;
    @@
    - extern
    T f(...);

and it was run with:

  $ git ls-files \*.{c,h} |
    grep -v ^compat/ |
    xargs spatch --sp-file contrib/coccinelle/noextern.cocci --in-place

This is not always straightforward though:

See commit 7027f50 (04 Sep 2019) by Denton Liu (Denton-L).
(Merged by Denton Liu -- Denton-L -- in commit 7027f50, 05 Sep 2019)

compat/*.[ch]: remove extern from function declarations using spatch

In 5545442 (*.[ch]: remove extern from function declarations using spatch, 2019-04-29, Git v2.22.0-rc0), we removed externs from function declarations using spatch but we intentionally excluded files under compat/ since some are directly copied from an upstream and we should avoid churning them so that manually merging future updates will be simpler.

In the last commit, we determined the files which taken from an upstream so we can exclude them and run spatch on the remainder.

This was the Coccinelle patch used:

@@
type T;
identifier f;
@@
- extern
  T f(...);

and it was run with:

$ 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 has some trouble dealing with __attribute__ and varargs so we ran the following to ensure that no remaining changes were left behind:

$ 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/

declaring a function extern means that its definition will be resolved at the time of linking, not during compilation.

Unlike regular functions, which are not declared extern, it can be defined in any of the source files(but not in multiple source files otherwise you'll get linker error saying that you've given multiple definitions of the function) including the one in which it is declared extern.So, in ur case the linker resolves the function definition in the same file.

I don't think doing this would be much useful however doing such kind of experiments gives better insight about how the language's compiler and linker works.


The reason it has no effect is because at the link-time the linker tries to resolve the extern definition (in your case extern int f()). It doesn't matter if it finds it in the same file or a different file, as long as it is found.

Hope this answers your question.

참고URL : https://stackoverflow.com/questions/856636/effects-of-the-extern-keyword-on-c-functions

반응형