왜 C 함수의 크기는 항상 1 바이트입니까?


87

를 사용하여 함수의 크기를 확인할 때 sizeof()항상 1 바이트를 얻습니다 . 이 1 바이트는 무엇을 의미합니까?

답변:


80

제약 위반이며 컴파일러 가이를 진단 해야 합니다. 그럼에도 불구하고 컴파일하면 프로그램에 정의되지 않은 동작이 있습니다 [실패 모드에 대한 설명을 위해 @Steve Jessop에게 감사하고 일부 컴파일러에서이를 허용하는 이유에 대해서는 @Michael Burr의 답변 참조 ] : From C11, 6.5.3.4./ 1:

sizeof연산자 기능 유형이 식에 적용되지 않는다


11
이는 제약 조건이며, 이는 준수 컴파일러에서 진단됨을 의미합니다. 컴파일러가 어쨌든 컴파일하면 (진단 한 경우) 동작은 정의되지 않습니다. 컴파일러가이를 진단하지 않으면 (예를 들어 gcc가를 사용하지 않는 경우 -pedantic) 비준수 컴파일러가 있고 모든 프로그램에 정의되지 않은 동작이있는 것입니다.
스티브 Jessop

1
이 동작은 GNU C 확장과 같은 범주에 속하지만, 왜 누군가 그 동작을 원하는지 모르겠습니다. 그래서 GNU 작성자가 왜 그것을 추가하려고했는지 모르겠습니다.
Steve Jessop

1
@SteveJessop이도 함께하는 것으로 -std=c11, 없습니다 gnu11 . 이것은 정말 이상한 컴파일러 확장입니다.
Kerrek SB

6
오! 나는 그것이 함수 포인터, 같은 방법으로 산술 수 있도록 내기 sizeof(void)GNU C로 1이다
스티브 Jessop에게

3
관련 -std=c11: 누군가가 -std=c*옵션을 광고 표준에 참조해야합니다 . 그들은 적합성 모드를 활성화하지 않고 단지 잘 구성된 프로그램이 컴파일되는 것을 막는 확장을 비활성화 할뿐입니다 (예를 들어 typeof, 잘 구성된 C 프로그램이 변수 이름으로 사용할 수 있기 때문에 키워드가되는 것과 같이 , gcc기본적으로이를 거부합니다) ). 잘못된 형식의 프로그램이 진단되지 않은 상태로 통과하도록 허용하는 확장을 추가로 비활성화하려면 -pedantic또는 -pedantic-errors.
스티브 Jessop

56

이것은 정의되지 않은 동작이 아닙니다. C 언어 표준에서는 sizeof연산자에 대한 제약 조건 위반이므로 함수 지정자 (함수 이름)와 함께 연산자를 사용할 때 진단이 필요합니다 sizeof.

그러나 C 언어의 확장으로 GCC는 void포인터와 함수 포인터 에 대한 산술을 허용 하며, 이는 a void또는 함수 의 크기 를 1. 결과적으로 sizeof연산자는 GCC 를 사용 1하여 void또는 함수를 평가합니다 . 참조 http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith를

GCC에 또는 옵션을 sizeof사용하여 이러한 피연산자와 함께 사용할 때 GCC가 경고를 발행하도록 할 수 있습니다 . 또는 .-pedantic-Wpointer-arith-Werror=pointer-arith


당신의 논리에 결함이 있습니다. C는 일부 UB에 대해 진단 메시지를 요구하지만 전부는 아닙니다. 진단이 있기 때문에 무언가가 행동을 정의했다고 말할 수는 없습니다.
MSalters

4
C에서는 모든 제약 위반에 대한 진단이 필요합니다 (5.1.1.3 C99 또는 C11의 진단). 제약 (C99 / C11의 3.8)은 "언어 요소의 설명이 해석되는 구문 적 또는 의미 론적 제약"이며 제약 조건을 따르지 않는 것은 해석 할 수 없다고 말하는 것처럼 보입니다. .
Michael Burr

3
그리고 명확하게 말하면 제약 조건 위반으로 인해 정의되지 않은 동작이 발생하지 않습니다. 구문 오류와 같은 오류입니다. 예를 들어, 표준에서는 " 제약 조건 외부에 나타나는"shall "또는"shall not "요구 사항을 위반하면 동작이 정의되지 않습니다"라고 말합니다. 제약 위반으로 인해 UB가 발생하는 경우 표준에서 여기에 제약 조건에없는 "shalls"및 "shall nots"만 언급하는 이유는 무엇입니까?
마이클 버

3
나는 sizeof함수가 UB가 아니라는 점을 제외하고는 UB에 대해 많이 언급하지 않았습니다 (다른 답변이 UB라고 언급했기 때문에 거의 언급했습니다). 하지만 문장을 구성하는 방식 때문에 혼란 스러웠을 것입니다. 더 명확하게. sizeof함수는 UB가 아닙니다 (여러 답변이 주장했듯이). 제약 위반입니다. 따라서 진단이 필요합니다. GCC는이를 확장으로 허용합니다.
마이클 버

2
@KerrekSB : OP는 아마도 GCC를 사용하고 있기 때문에 진단을받지 못합니다. 이것은 C 언어 확장으로이 사용을 허용합니다.
마이클 버

13

이것은 컴파일러 작성자가 귀신이 당신의 코에서 날아 오르게하는 대신 1의 값을 결정했음을 의미합니다. (사실, 그것은 sizeof우리에게 다음과 같은 표현을 주었던 또 다른 정의되지 않은 사용이었습니다 . "이것이 첫 번째 요구라면 C 컴파일러 자체가 진단을 발행해야합니다. 당신의 프로그램에서 발생하는 진단은 구문 규칙이나 제약의 추가 위반에 대한 추가 진단을 발행 할 수있는 것처럼 (그런데 문서화 된 진단 메시지가 될 수있는) 악마가 당신의 코에서 날아 오르게 할 수도 있습니다. 어떤 이유로 든 선택). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

이것으로부터 컴파일러가 정의되지 않은 구조에 대한 응답으로하기로 결정한 모든 것에 대한 속어 "코 악마"가 있습니다. 1이 경우이 컴파일러의 비강 악마입니다.


@IlmariKaronen 나는 C (및 C ++)에 대한 대부분의 답변이 일반적인 언어에 구애받지 않는 원칙이나 이와 같은 역사적 덩어리에 대한 이유가 있음을 인정해야 할 것입니다. 내 C 경험 : 그 자체로 역사에 경계한다
존 한나

7

다른 사람들이 지적했듯이 sizeof ()는 유효한 식별자를 사용할 수 있지만 함수 이름에 대해 유효한 (정직하고 유효한) 결과를 반환하지 않습니다. 또한 "코에서 나오는 악마"증후군을 유발할 수도 있고 그렇지 않을 수도 있습니다.

프로그램 함수 크기를 프로파일 링하려면 중간 결과 디렉토리 (.obj / .o로 컴파일되거나 결과 이미지 / 실행 파일이있는 위치)에있는 링커 맵을 확인하십시오. 때때로이 맵 파일을 생성하거나 생성하지 않는 옵션이 있습니다. 컴파일러 / 링커에 따라 다릅니다.

함수에 대한 포인터의 크기를 원하면 모두 동일한 크기, 즉 cpu의 주소 지정 단어 크기입니다.


1
"확실히 할 수도 있고 아닐 수도있다"는 말은 어떤 것입니까 ??? 말 그대로 모든 것이 사실이 아닙니까?
Kerrek SB

@KerrekSB 예, 그러나 여기서는 아무것도 할 수도 있고하지 않을 수도 있으며 여전히 규칙 내에 있습니다. 컴파일러가 컴파일을 거부 할 수도 있고 거부하지 않을 수도 int x = 1;있지만 표준 준수 컴파일러에는 그중 하나만 허용됩니다. 로 sizeof()함수에 적용되고, 그것은 또는 설정 값을 반환하거나, 컴파일을 거부하거나 시간에 특정 레지스터에있어 무엇을 기준으로 임의의 값을 반환하지 않을 수 있습니다. 문자 그대로의 비강 악마는 가능성이 적지 만 표준 문자 내에 있습니다.
존 한나

@kerrek 아무것도 아니라면 참일 수도 있고 거짓이 아닐 수도 있습니다.
jpinto3912

1
함수에 대한 포인터의 크기를 알고 싶다면 함수 sizeof에 대한 포인터에 적용하십시오 .
alexis 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.