programing

소스 파일에도 'external C'를 추가해야 합니까?

muds 2023. 6. 10. 09:50
반응형

소스 파일에도 'external C'를 추가해야 합니까?

나는 최근에 외부 "C"가 함수들을 위해 소스 파일에 추가된 코드를 발견했습니다.또한 선언된 헤더 파일에 추가되었습니다.

저는 헤더 파일에 '외부 C'를 추가하면 충분하다고 생각했습니다.

외부 "C" 블록은 어디에 추가해야 합니까?

업데이트: CPP 컴파일러를 사용하여 C 코드를 컴파일하고 헤더 파일의 모든 함수에 대해 외부 "C" 가드를 추가했다고 가정합니다(즉, 내 모든 함수는 헤더에 프로토타입이 있음). 그러나 소스 파일에서는 추가하지 않았습니다.이것이 문제를 일으킬까요?

당신 말이 맞으니깐

extern "C" { ... }

스타일 가드(style guards)는 일부 함수가 "C++" 링크가 아닌 "C" 링크임을 선언합니다(일반적으로 오버로드된 함수와 같은 것을 지원하기 위해 추가적인 이름 장식이 있습니다).

물론 목적은 C++ 코드가 일반적으로 라이브러리에 있는 C 코드와 인터페이스할 수 있도록 하는 것입니다.라이브러리의 헤더가 C++을 염두에 두고 작성되지 않은 경우 C++대한 가드를 포함하지 않습니다.

C++을 염두에 두고 작성된 C 헤더에는 다음과 같은 것이 포함됩니다.

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

C++ 프로그램이 올바른 연결을 확인합니다.하지만, 모든 라이브러리가 C++을 염두에 두고 작성된 것은 아니기 때문에, 때때로 당신은 해야만 합니다.

extern "C" {
#include "myclibrary.h"
}

정확한 연결을 위해.헤더 파일이 다른 사용자가 제공한 경우에는 변경하는 것이 좋지 않습니다(쉽게 업데이트할 수 없기 때문에). 따라서 헤더 파일을 사용자의 가드(사용자의 헤더 파일에 포함되어 있을 수 있음).

extern "C"AFAIK는 ANSIC가 아니므로 전처리기 가드가 없으면 일반 C 코드에 포함될 수 없습니다.

편집 내용에 대한 응답:

C++ 컴파일러를 사용하는 경우 헤더 파일에서 함수를 외부 "C"로 선언하면 구현 파일에서도 해당 함수를 외부 "C"로 선언할 필요가 없습니다.C++ 표준의 섹션 7.5부터(광산 강조):

동일한 함수나 객체의 두 선언이 서로 다른 링크 규격을 지정하는 경우(즉, 이들 선언의 링크 규격이 서로 다른 문자열 리터럴을 지정하는 경우), 같은 변환 단위에 선언이 나타나면 프로그램이 잘못 구성됩니다.선언이 다른 변환 단위로 나타나는 경우 단일 정의 규칙이 적용됩니다.C++ 연결이 있는 함수를 제외하고, 연결 사양이 없는 함수 선언은 해당 함수에 대한 첫 번째 연결 사양 앞에 있으면 안 됩니다.함수는 명시적인 연결 사양이 확인된 후 연결 사양 없이 선언될 수 있습니다. 이전 선언에서 명시적으로 지정된 연결은 이러한 함수 선언의 영향을 받지 않습니다.

링크 사양이 실수로 분산될 가능성이 있기 때문에(예를 들어 링크 사양이 포함된 헤더 파일이 구현 파일에 포함되지 않은 경우) 좋은 방법이라고 확신할 수 없습니다.구현 파일에 명시적으로 기재하는 것이 좋다고 생각합니다.

다른 원본 파일에 포함된 모든 항목만 넣으면 됩니다.

가지 관용구를 사용하면 소스 파일을 포함한 사용자를 찾을 수 있습니다.

다른 파일에 포함되는 모든 파일에 추가해야 합니다.

일반적으로 소스 파일은 포함되지 않습니다.

사파니아

질문이 무엇에 대해 묻고 있었는지 훨씬 더 명확하게 바뀌었습니다.이 답변은 헤더 파일에 여러 개 포함되는 것에 대한 가드를 논의하는 것인지 적어도 논쟁의 여지가 있는 원래 질문을 다루었습니다. 이것이 제 답변이 다루는 것입니다.분명히 그때 질문이 지금처럼 명확했다면 이런 답변을 제출하지 않았을 것입니다.


원답

아니요, 경비원도 C 코드에 포함시킬 필요는 없습니다.

만약 헤더 파일이 '헤더'라면.h'는 말합니다.

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
...
#endif

그러면 소스 파일 'source.c'가 다음과 같이 말하는 것이 완벽하게 안전합니다.

#include "header.h"

또한 다른 헤더에 'header'를 포함하는 것도 안전합니다.h'의

그러나 사람들은 헤더 파일을 열고 파일을 읽는 데 시간이 걸려 컴파일 속도가 느려지기 때문에 때때로 다음과 같은 작업을 수행합니다.

#ifndef HEADER_H_INCLUDED
#include "header.h"
#endif

즉, 'source.c'에 포함된 다른 헤더에 이미 'header.h'가 포함되어 있으면 '#include'는 재처리되지 않습니다. (또는 'header'인 경우)h'는 이미 'source.c'에 직접 포함되어 있지만, 그것은 어리석은 나팔입니다.)

따라서 컴파일 성능을 최적화하려는 시도일 가능성이 높습니다.그것이 당신에게 많은 것을 사준다는 것은 확실하지 않습니다. 현대의 C 전처리기는 문제에 대해 상당히 지능적이며 가능하다면 파일을 다시 포함하는 것을 피할 것입니다.그리고 항상 'source.c'의 테스트에 오타가 있을 위험이 있습니다(#ifndef HEARER_H_INCLED, 아마도). 이 경우 사전 처리기가 관련 없는 조건을 테스트한 다음 'header'를 포함하기 때문에 테스트가 컴파일을 느리게 합니다.결국은 h'입니다.헤더 자체가 보호되거나 보호되어야 하는 '안전해야 합니다.

'source.c'에서도 '#define HEADER_H_INCLED'를 실행하는 코드가 보이면 문제가 발생합니다.#define은 #include 앞이나 뒤에 있어야 하며 일반적인 기법으로는 적합하지 않습니다.

  • 'source.c'가 'header.h'를 포함하기 전에 '#define HEADER_H_INCLUED'를 수행하는 경우, 가드가 'header.h'에 나타나면 헤더의 내용은 포함되지 않습니다.가드가 'header.h'에 나타나지 않으면 문제가 해결됩니다.
  • 'source.c'가 'header.h'를 포함한 후 '#define HEADER_H_INCLUDE'를 수행하면, 가드가 'header.h'에 나타나면 HEADER_H_INCLUDE가 긍정적으로 재정의됩니다.만약 헤더라면.h'에는 가드가 포함되어 있지 않지만 'filename'을 포함하는 파일이 포함되어 있습니다.h', 다중 포함으로부터 보호되지 않습니다.

헤더 본문은 '#define HEADER_H_INCLUED' 뒤에 나타납니다.중첩된 항목에 '헤더'가 포함된 경우 다시 보호됩니다.h'의

외부 c' 전처리기를 말하는 건가요?함수는 함수 정의에 있어야 하며 함수 호출이 컴파일된 이진에 저장되는 방식에 영향을 미칩니다.컴파일된 c++를 C로 컴파일된 c와 함께 링크하는 경우에만 정말 필요합니다(.cpp 파일의 c와는 대조적).

"C" 가드는 두 가지 목적이 있습니다.

  1. 코드가 컴파일되면 C++ 컴파일러/링커가 아닌 사용자가 사용할 수 있는 방식으로 함수가 내보내집니다(C++ 이름 망글링 등 없음).
  2. C++ 컴파일러가 당신의 헤더 파일을 사용할 때, 그것은 그것이 C 방식으로 심볼들을 바인딩해야 한다는 것을 알게 될 것이고, 이것은 결과 프로그램이 성공적으로 연결되도록 할 것입니다.그들은 C++ 컴파일러가 아닌 컴파일러에 대한 의미를 가지고 있지 않지만 기호가 (1)에서 C 스타일로 생성되었기 때문에 이것이 원하는 효과입니다.

구현 파일에도 "C" 가드가 있는 헤더를 포함하므로 컴파일러가 컴파일 시 기호를 생성하는 방법에 대한 정보를 사용할 수 있으며 컴파일러는 C++ 컴파일러가 아닌 다른 컴파일러가 사용할 수 있는 방식으로 기호를 생성합니다.따라서 헤더 파일이 구현 파일에 포함되어 있는 한 헤더 파일에 외부 "C"만 지정하면 됩니다.

우리는 항상 헤더 정의에 외부 "C"만 추가했지만, 이를 통해 C++ 코드는 오류 없이 오버로드를 통해 다른 서명으로 함수를 구현할 수 있지만 심볼 정의를 교란시키지 않기 때문에 링크 시 이 불일치 함수를 사용합니다.헤더와 정의가 모두 외부 "C"인 경우 Visual Studio 2017 및 g++ 5.4에서 일치하지 않는 서명이 오류를 생성합니다.

다음 코드는 Visual Studio 2017 및 g++ 5.4에 대해 오류 없이 컴파일됩니다.

extern "C" {
    int test(float a, int b);
}
int test(int b)
{
    return b;
}

이 경우 gcc가 기호 이름을 망치는 것처럼 보이지만 Visual Studio 2017은 그렇지 않습니다.

그러나 정의와 함께 외부 "C"를 포함하면 컴파일 시 불일치가 발견됩니다.

extern "C" {
    int test(float a, int b);
}
extern "C" int test(int b)
{
    return b;
}

g++에서 다음 오류가 발생합니다.

 g++ -c -o test.o test.cpp
 test.cpp: In function ‘int test(int)’:
 test.cpp:4:26: error: conflicting declaration of C function ‘int test(int)’
 extern "C" int test(int b)
                      ^
 test.cpp:2:9: note: previous declaration ‘int test(float, int)’
 int test(float a, int b);

또는 cl과 함께

cl /c test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27042 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(4): error C2733: 'test': second C linkage of overloaded function not allowed
test.cpp(2): note: see declaration of 'test'

헤더 파일에 extern을 사용하고 나머지 소스 파일에 해당 파일이 포함되어 있는 경우 소스 파일에 extern을 사용할 필요가 없습니다.

제가 기억하기로는 모든 함수 선언은 기본적으로 "외부"로 간주되므로 명시적으로 지정할 필요가 없습니다.변수와 함께 사용할 수도 있기 때문에 이 키워드가 무용지물이 되는 것은 아닙니다(그리고 그 경우 - 이것이 연결 문제를 해결하는 유일한 해결책입니다).하지만 기능을 사용하면 - 네, 선택 사항입니다.

좀 더 자세한 답변은 다른 소스 코드 파일에 컴파일된 변수를 사용할 수 있지만 변수에 대한 메모리를 예약하지는 않는다는 것입니다.따라서 extern을 사용하려면 함수 내가 아닌 최상위 수준의 변수에 대한 메모리 공간이 포함된 소스 코드 파일 또는 라이브러리 단위가 있어야 합니다.이제 다른 소스 코드 파일에서 동일한 이름의 외부 변수를 정의하여 해당 변수를 참조할 수 있습니다.

일반적으로 외부 정의의 사용은 피해야 합니다.관리할 수 없는 코드와 찾기 어려운 오류가 쉽게 발생합니다.물론 다른 솔루션이 비실용적인 경우도 있지만, 드물기는 합니다.예를 들어 stdin 및 stdout은 stdin에서 FILE* 유형의 외부 배열 변수에 매핑되는 매크로입니다.h; 이 배열의 메모리 공간이 표준 C-라이브러리 단위에 있습니다.

언급URL : https://stackoverflow.com/questions/2168241/is-it-required-to-add-extern-c-in-source-file-also

반응형