C와 링크의 잠정적인 정의
두 개의 파일로 구성된 C 프로그램을 생각해 보십시오.
f1.c:
int x;
f2.c:
int x=2;
제가 C99 표준의 6.9.2항을 읽은 것은 이 프로그램이 거부되어야 한다는 것입니다.6.9.2에 대한 내 해석에 따르면 변수는x
가 되어 있습니다.f1.c
이 인 정의는 단위의 (에는) 하만이잠인정실정되끝고내제의가에마, (생에각그)는▁if▁as▁but▁therefore▁(,다합ition▁defin▁becomes내니ition▁tentative▁thisin▁at▁an▁(▁shouldation▁the처럼 행동해야 합니다.f1.c
에는 정를포니다습함의 되어 있습니다.int x=0;
.
모든 컴파일러(그리고 중요한 링커)를 사용하여 시도할 수 있었지만, 이런 일은 일어나지 않았습니다.한 모든 파일을 하고, 은 위의 두 파일을 연결합니다.x
두 파일 모두에서 2입니다.
이러한 현상이 우연히 발생하거나 표준에 필요한 기능 외에 "쉽게" 제공할 수 있는 기능인지 의심스럽습니다.생각해보면 0으로 명시적으로 초기화된 변수와 달리 이니셜라이저가 없는 글로벌 변수에 대한 링커의 특별한 지원이 있다는 것을 의미합니다.누군가가 포트란을 컴파일하려면 링커 기능이 필요할 수도 있다고 말했습니다.그것은 합리적인 설명이 될 것입니다.
이것에 대한 생각이 있습니까?표준에 대한 다른 해석?이 f1.c
그리고.f2.c
함께 연결되는 것을 거부합니까?
참고: 질문은 정적 분석의 맥락에서 발생하기 때문에 중요합니다.두 파일이 어떤 플랫폼에서 연결되는 것을 거부할 수 있다면 분석가가 불만을 제기해야 하지만, 모든 컴파일 플랫폼이 이를 수락한다면 경고할 이유가 없습니다.
C에서 외부 변수란 무엇입니까?를 참조하십시오.이것은 정보를 제공하는 부록 J의 C 표준에 공통 확장으로 언급되어 있습니다.
J.5.11 다중 외부 정의
extern 키워드를 명시적으로 사용하든 사용하지 않든 객체 식별자에 대해 둘 이상의 외부 정의가 있을 수 있습니다. 정의가 일치하지 않거나 둘 이상이 초기화되면 동작이 정의되지 않습니다(6.9.2).
경고문
@litb가 여기서 지적하고 교차 참조 질문에 대한 내 대답에서 언급했듯이 글로벌 변수에 대해 다중 정의를 사용하면 정의되지 않은 동작이 발생합니다. 이는 표준의 "모든 것이 일어날 수 있습니다"라는 표현 방식입니다.발생할 수 있는 것 중 하나는 프로그램이 예상대로 작동한다는 것입니다. 그리고 J.5.11은 대략 "당신은 당신이 받을 자격이 있는 것보다 더 자주 운이 좋을 수 있습니다."라고 말합니다.으로 "" " " " " " " " " " " 를 하거나 하지 않는 변수의 입니다.extern
키워드 - 엄격하게 준수하는 프로그램이 아니며 모든 곳에서 작동하도록 보장되지 않습니다.동등하게: 표시될 수도 있고 표시되지 않을 수도 있는 버그를 참조됩니다.
참고 항목소스 파일 간에 변수를 공유하려면 어떻게 해야 합니까?
Sven이 코멘트에서 언급한 바와 같이, "사용 방법extern
GCC는 비교적 최근에 기본 규칙을 변경했습니다.GCC 10.x(2020년 5월 이후) 이상 버전에서 기본 컴파일 모드는 다음을 사용합니다.-fno-common
가 " 이버 전 에 사 모 었 습 되 니 용 다 가 드 전 기 본 서 는 니 ▁whereas 다-fcommon
새로운 행동은 C 표준이 엄격한 준수를 위해 요구하는 것인 여러 잠정적 정의를 벗어나지 않는다는 것을 의미합니다.
만약 당신이 GCC를 사용하고 (ab) 복수의 잠정적인 정의를 사용하는 코드를 가지고 있다면, 당신은 추가할 수 있습니다.-fcommon
컴파일 프로세스에 적용하면 이전과(와 같이 작동합니다.는 최대한이식할 수 있는 것이 , 으로는 각 파일변수를 에이 모두 하다는 .그리고 장기적으로 코드를 수정하여 각 변수가 하나의 소스 파일(해당 변수를 사용해야 하는 모든 프로그램과 연결됨)에 적절하게 정의되고 변수를 사용하는 소스 파일이 모두 포함할 수 있는 하나의 헤더에 적절하게 선언되도록 하는 것이 좋습니다(그리고 변수를 정의하는 소스 파일도 다음을 포함해야 합니다).e 헤더를 사용하여 일관성을 보장합니다.
표준에 대한 "공통 확장"이라는 것이 있는데, 변수가 한 번만 초기화되는 한 변수를 여러 번 정의할 수 있습니다.http://c-faq.com/decl/decldef.html 을 참조하십시오.
링크된 페이지에는 이것이 유닉스 플랫폼과 관련이 있다고 나와 있습니다. -- c99도 c89와 동일한 것 같습니다. -- 아마도 어떤 종류의 사실상 표준을 형성하기 위해 더 많은 컴파일러에 채택되었을 수도 있습니다.재밌는.
이것은 olovb의 논평에 대한 나의 대답을 명확히 하기 위해서입니다.
"intx;"에서 컴파일된 개체 파일에 대한 nm의 출력.이 플랫폼에서는 기호 앞에 '_'가 붙습니다. 즉, 변수 x가 _x로 나타납니다.
00000000 T _main
U _unknown
00000004 C _x
U dyld_stub_binding_helper
"int x=1;"에서 컴파일된 개체 파일에 대한 nm 출력
00000000 T _main
U _unknown
000000a0 D _x
U dyld_stub_binding_helper
"int x=0;"에서 컴파일된 개체 파일에 대한 nm 출력
00000000 T _main
U _unknown
000000a0 D _x
U dyld_stub_binding_helper
"external int x;"에서 컴파일된 객체 파일에 대한 nm 출력
00000000 T _main
U _unknown
U dyld_stub_binding_helper
EDIT: "external int x;"에서 컴파일된 개체 파일에 대한 nm 출력. 여기서 x는 실제로 함수 중 하나에서 사용됩니다.
00000000 T _main
U _unknown
U _x
U dyld_stub_binding_helper
언급URL : https://stackoverflow.com/questions/1490693/tentative-definitions-in-c-and-linking
'programing' 카테고리의 다른 글
도커: 도커 컨테이너의 로그를 올바르게 지우는 방법은 무엇입니까? (0) | 2023.08.31 |
---|---|
NSMutableAttributeString에서 링크 색상 변경 (0) | 2023.08.31 |
MySQL/MariaDB의 ORLite 날짜(밀리초 정밀도) (0) | 2023.08.31 |
CSS 클래스 .foo.bar (공백 없음)과 .foo.bar(공백 있음)의 차이점은 무엇입니까? (0) | 2023.08.31 |
PowerShell에서 변수가 8자 이상인지 테스트하려면 어떻게 해야 합니까? (0) | 2023.08.31 |