programing

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

javaba 2022. 11. 25. 21:20
반응형

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

C의 .extern★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★는 음음을 정의할 때 이렇게 생각했어요.extern int f();파일 범위 밖에서 구현하도록 강제합니다.하지만 둘 다 알아냈죠

extern int f();
int f() {return 0;}

그리고.

extern int f() {return 0;}

gcc의 경고 잘합니다.하였습니다.gcc -Wall -ansi은 심지어 도 않을 이다.//comments.comments.comments.

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)
{
   if (! stop_now) {
      printf("Hello, world!\n");
      sleep(30);
   }
}

보시다시피 foo.c와 bar.c 사이에는 공유 헤더가 없습니다만, bar.c는 링크되어 있을 때 foo.c에 선언된 것이 필요하며, foo.c는 링크되어 있을 때 bar.c의 함수가 필요합니다.

exter'를 사용하면 링크 시 검색(비정적)되는 것을 컴파일러에 알립니다.나중에 발생하므로 현재 패스로는 아무것도 예약하지 마십시오.이 점에서 함수와 변수는 동등하게 취급됩니다.

모듈 간에 글로벌하게 공유할 필요가 있어 헤더에 넣거나 초기화하지 않을 경우 매우 유용합니다.

엄밀히 말하면 라이브러리 공개 헤더의 모든 함수는 '외부'이지만, 컴파일러에 따라서는 그렇게 라벨을 붙이는 것은 거의 또는 전혀 도움이 되지 않습니다.대부분의 컴파일러는 스스로 알아낼 수 있습니다.보시다시피 이러한 함수는 실제로 다른 곳에 정의되어 있습니다.

위의 예에서 main()은 hello world를 한 번만 출력하지만 bar_function()을 계속 입력합니다.또한 이 예에서는 bar_function()은 단순한 예이므로 반환되지 않습니다.이것이 충분히 실용적이지 않다고 생각될 경우 신호가 처리될 때(따라서 휘발성) stop_now가 변경된다고 상상해 보십시오.

외부부착은 신호 핸들러, 뮤텍스 등 헤더나 구조물에 넣고 싶지 않은 경우에 매우 유용합니다.대부분의 컴파일러는 오브젝트가 정의되어 있는 모듈에서 메모리를 예약하는 것을 알고 있기 때문에 외부 오브젝트용으로 메모리를 예약하지 않도록 최적화합니다.그러나 공공 기능을 프로토타입으로 만들 때 최신 컴파일러로 지정하는 것은 의미가 없습니다.

도움이 되었으면 좋겠다:)

제가 기억하는 한, 모든 함수 선언은 기본적으로 "외부"로 간주되기 때문에 명시적으로 지정할 필요는 없습니다.

이 키워드는 변수와 함께 사용할 수 있기 때문에 이 키워드는 무용지물이 되지 않습니다(그리고 이 경우 링크 문제를 해결할 수 있는 유일한 해결책입니다.다만, 기능에서는, 옵션입니다.

함수 정의와 기호 선언이라는 두 가지 개념을 구분해야 합니다."extern"은 링크 수식자이며 나중에 참조되는 기호가 정의되는 위치에 대한 컴파일러에 대한 힌트입니다(힌트는 "여기에 없습니다").

내가 글을 쓴다면

extern int i;

C 파일의 파일 범위(함수 블록 외부)에서 "변수는 다른 곳에서 정의될 수 있습니다"라고 말합니다.

extern int f() {return 0;}

는 함수 f의 선언이자 함수 f의 정의입니다.이 경우 정의는 외부보다 우선합니다.

extern int f();
int f() {return 0;}

는 처음에 선언한 후 정의를 나타냅니다.

「」의 extern파일 범위 변수를 선언하고 동시에 정의할 경우 잘못된 것입니다.를 들어 '예'라고 하면,

extern int i = 4;

는 컴파일러에 따라 오류 또는 경고를 표시합니다.

「 」의 extern는 변수의 정의를 명시적으로 회피하는 경우에 편리합니다.

설명하겠습니다.

예를 들어 a.c 파일에 다음이 포함되어 있다고 합시다.

#include "a.h"

int i = 2;

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

a.h 파일에는 다음이 포함됩니다.

extern int i;
int f(void);

파일 b.c에는 다음이 포함됩니다.

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

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

헤더 내의 extern은 링크 단계 중에 컴파일러에게 "이것은 선언이며 정의가 아닙니다."라고 알려주기 때문에 유용합니다.i를 정의하는 a.c 행을 삭제하고 공간을 할당하고 값을 할당하면 정의되지 않은 참조를 사용하여 프로그램이 컴파일되지 않습니다.이것은 개발자에게 변수를 참조했지만 아직 정의하지 않았음을 알려줍니다. 「를 생략하고, 「exter」, 「exter」를 합니다.int i = 2컴파일되어 line으로 됩니다.

파일 범위 변수는 함수의 맨 위에서 선언하는 블록 범위 변수와 달리 명시적으로 값을 할당하지 않으면 기본값 0 또는 NULL로 암묵적으로 정의됩니다.extern 키워드는 이 암묵적인 정의를 회피하기 때문에 실수를 회피하는 데 도움이 됩니다.

함수의 경우 함수 선언에서 키워드는 실제로 용장합니다.함수 선언에는 암묵적인 정의가 없습니다.

인라인 함수에는 특별한 규칙이 있습니다.extern 확장입니다 C99에 것에 해 주세요GNU는 C99 또는 GNU 확장입니다.

함수의 경우, 「」는 다음과 .extern는 기본적으로 켜져 있기 때문에 필요하지 않습니다.

C++면 되다를 들어, 「」라고 하는 것은,extern "C"는, CC또, C++ 에 은 다릅니다.C++로 하다inline.

IOW, 외부장치는 용장성이 있어 아무것도 하지 않습니다.

그래서 10년 후:

  • Coccinelle과 같은 코드 변환 툴은 함수 선언에서 삭제에 플래그를 붙이는 경향이 있습니다.
  • 같은 코드베이스는 그 결론에 따라 삭제된다.extern(Git 2.22, 2019년 Q2).

Denton Liu()Denton-L의 commit ad6dad0, commit b199d71, commit 5545442(2019년 4월 29일)를 참조하십시오.
(2019년 5월 13일 Junio C Hamano에 의해 병합)

*.[ch] : ★★★extern함수 선언에서 사용

.extern함수 선언으로부터.

해서'어울리지 않다'의 몇 예를 제거해 주세요.externCoccinelle 。
Coccinelle co 、 Coccinelle co co with with with with with with with with with with with with with with with 기능에 문제가 있음을 해 주십시오.__attribute__하여 "vargs"를 설정합니다.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()Denton-L의 commit 7027f50(2019년 9월 4일)을 참조하십시오.
(2019년 9월 5일 7027f50에서 Denton Liu에 의해 병합됨)

compat/*.[ch] : ★★★extern를 사용한

(5545442 †)*.[ch] : ★★★extern를 사용한 에서 2019-04-29, Git v2.22.0-rc0)을 사용한 함수 하였습니다.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/

코시넬은 코시넬이 이 문제를 해결하는데 어려움을 겪고 있다.__attribute__하여 남은 .varargs 및 varargs 、 varargs 、 vararargs 、 vararargs 。

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

2.24 의 스플리어스 Git 2.24 (2019년 4분기)가 .extern롭됩니니다다

Emily Shaffer()nasamuffin의 commit 65904b8(2019년 9월 30일)을 참조하십시오.
도움말: Jeff King()peff
Denton Liu()Denton-L의 commit 8464f94(2019년 9월 21일)를 참조하십시오.
도움말: Jeff King()peff
(2019년 10월 7일 Junio C Hamano에 의해 병합됨----commit 59b19bc에서)

promisor-remote.h : 드드extern function declaration으로

시 마다 이 에는 새로운 함수 선언이 .extern.
단, 5545442부터 (*.[ch] : ★★★extern를 한 함수 spatch에 함수 되지 않도록

스플리어스들을 삭제합니다.externs.

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 기억종별 지정자 외부로 선언된 식별자에 대해, 그 식별자의 사전 선언이 내부 또는 외부 링크를 지정하는 경우, 그 후의 선언에서의 식별자의 링크는 사전 선언에서 지정된 링크와 동일하다.사전 선언이 표시되지 않거나 이전 선언이 링크를 지정하지 않은 경우 식별자에는 외부 링크가 있습니다.

5 함수의 식별자 선언에 스토리지 클래스 지정자가 없는 경우, 그 링크는 스토리지 클래스 지정자 외부와 함께 선언된 것과 동일하게 결정된다.개체의 식별자 선언에 파일 범위가 있고 스토리지 클래스 지정자가 없는 경우 해당 링크는 외부입니다.

으로 C로 됩니다.extern키워드가 실제로 기술되어 있는지 여부에 관계없이,

암호는 다음과 같습니다.

    int f() {return 0;}

컴파일러는 다음과 같이 취급합니다.

    extern int f() {return 0;}

와 그 에 있는 함수의 가 없습니다.extern키워드를 지정합니다.상세한 것에 대하여는, https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/ 를 참조해 주세요.

이것이 는 링크 가 외부 이 경우, 「」는 「」의 정의입니다).extern int f()같은 파일이나 다른 파일 중 어느 것이 발견되더라도 상관없습니다.

이게 당신의 질문에 답하길 바랍니다.

함수 외부를 선언하는 것은 그 정의가 컴파일이 아닌 링크 시에 해결된다는 것을 의미합니다.

extern으로 선언되지 않은 일반 함수와 달리 extern으로 선언된 함수를 포함하여 모든 소스 파일에서 정의할 수 있습니다(단, 여러 소스 파일에서는 정의할 수 없습니다).따라서 링커가 동일한 파일에서 함수 정의를 해결하는 경우입니다.

이렇게 하는 것은 그다지 유용하지 않다고 생각합니다만, 이러한 종류의 실험을 하는 것은 언어의 컴파일러와 링커가 어떻게 작동하는지 더 잘 알 수 있습니다.

extern키워드는 함수 또는 변수가 외부 링크를 가지고 있음을 컴파일러에 알립니다.즉, 정의된 파일 이외의 파일에서 볼 수 있습니다.이런 의미에서 그것은 와 반대되는 의미를 갖는다.static키워드를 지정합니다. 이상하다extern정의 시 다른 파일은 정의를 볼 수 없기 때문에(또는 여러 개의 정의가 생성될 수 있습니다).보통 당신이 넣는 것은extern(헤더 파일 등) 외부 가시성이 있는 시점의 선언에서 정의를 다른 위치에 배치합니다.

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

반응형