sizeof (x ++)가 왜 x를 증가시키지 않습니까?


505

다음은 dev C ++ 창에서 컴파일 된 코드입니다.

#include <stdio.h>

int main() {
    int x = 5;
    printf("%d and ", sizeof(x++)); // note 1
    printf("%d\n", x); // note 2
    return 0;
}

노트 1x 을 실행 한 후 6이 될 것으로 예상 됩니다 . 그러나 출력은 다음과 같습니다.

4 and 5

아무도 노트 1x 후에 왜 증가하지 않는지 설명 할 수 있습니까 ?


37
내가 DevC ++은 아주 오래된 오래된 컴파일러를 사용하고 있습니다 것입니다, 당신은, 예를 들어 Codeblocks 이클립스 또는 Visual Studio 새로운 IDE로 업그레이드 할 수 있습니다
톰 J 노웰

4
++ x는 x ++, cygwin 및 gcc 3.4.4와 동일한 결과를 생성합니다.
yehnan

6
@Tim Pletzcker 첫 번째 값은 변수 자체가 아니라 변수의 크기이기 때문입니다.
Surfbutler

이 답변 과 병합되어 내 답변이 추가되었습니다. 내 답변은 실제로 VLAs다른 사람이없는 경우 런타임 평가를 얻는 방법을 보여줍니다 .
Shafik Yaghmour 2014

2
이런 종류의 글씨는 바람직하지 않은 부작용을 일으킬 수 있으므로 피해야합니다. 귀하의 질문은 이미 그들 중 하나입니다.
user666412

답변:


537

로부터 C99 표준 (강조는 나의 것)

6.5.3.4/2

sizeof 연산자는 피연산자의 크기 (바이트)를 산출하며 표현식 또는 유형의 괄호로 묶은 이름 일 수 있습니다. 크기는 피연산자의 유형에 따라 결정됩니다. 결과는 정수입니다. 피연산자의 유형이 가변 길이 배열 유형 인 경우 피연산자가 평가됩니다. 그렇지 않으면 피연산자가 평가되지 않고 결과는 정수 상수입니다.


51
"피연산자의 유형이 가변 길이 배열 유형 인 경우 피연산자가 평가됩니다"와우! 나는 그것을 깨달았다
코스

6
가변 길이 배열 유형은 무엇을 의미합니까? 피연산자가 배열을 의미합니까? 이 경우 코드는 배열이 아닙니다. 당신은 나를 위해 일을 정리할 수 있습니까?
Neigyl R. Noval

37
가변 길이 배열은 Nstdin 및 make에서 읽는 경우와 같이 크기가 컴파일 중에 알 수없는 값으로 선언 된 배열 int array[N]입니다. 이것은 C ++에서 사용할 수없는 C99 기능 중 하나입니다.
코스

21
@LegendofCage, 특히 이것은 sizeof(int[++x])(실제로, 나쁜 아이디어입니다) 어쨌든 ++평가 될 수 있음을 의미합니다.
Jens Gustedt

3
@Joe Wreschnig은 : 그것은에 의해 평가되고 gcc, clang과에서 ideone.com/Pf7iF
JFS

190

sizeofA는 컴파일 시간 연산자 그래서 편집시에, sizeof그 연산은 결과 값으로 교체하자. 피연산자되어 평가되지 전혀 (그것이 가변 길이 배열 인 경우는 제외); 결과 의 유형 만 중요합니다.

short func(short x) {  // this function never gets called !!
   printf("%d", x);    // this print never happens
   return x;
}

int main() {
   printf("%d", sizeof(func(3))); // all that matters to sizeof is the 
                                  // return type of the function.
   return 0;
}

산출:

2

short내 컴퓨터에 2 바이트를 차지합니다.

함수의 리턴 유형을 다음으로 변경 double:

double func(short x) {
// rest all same

8출력으로 줄 것입니다 .


12
때때로-가능하다면 컴파일 시간입니다.
Martin Beckett

10
-1, 이는 인정 된 (정확한) 답변과 모순되며 표준을 인용하지 않기 때문입니다.
sam hocevar

1
문자열로 작업 할 때 sizeof () 연산자의 컴파일 타임 분석에 좋은 이점이 있습니다. 문자열을 구성하는 문자 배열을 런타임에 널 종료 자로 스캔해야하는 strlen ()을 사용하는 대신 인용 문자열로 초기화 된 문자열이있는 경우 sizeof (quoted_string)은 컴파일 시간으로 알려져 있습니다. 따라서 런타임에. 작은 일이지만 인용 된 문자열을 루프에서 수백만 번 사용하면 성능이 크게 달라집니다.
user2548100

루프에서 실제로 수백만 번을 사용한다면 루프에서 길이 계산을 고려하는 것이 훨씬 합리적이지 않습니까? 코드에 수백만 가지의 서로 다른 하드 코딩 된 상수 가 없기를 바랍니다 . : -o
Veky

47

sizeof(foo) 컴파일 타임에 표현식의 크기를 찾기 위해 정말로 열심히 노력합니다.

6.5.3.4 :

sizeof 연산자는 피연산자의 크기 (바이트)를 산출하며 표현식 또는 유형의 괄호로 묶은 이름 일 수 있습니다. 크기는 피연산자의 유형에 따라 결정됩니다. 결과는 정수입니다. 피연산자의 유형이 가변 길이 배열 유형 인 경우 피연산자가 평가됩니다. 그렇지 않으면 피연산자가 평가되지 않고 결과는 정수 상수입니다.

한마디로 : 가변 길이 배열은 런타임에 실행합니다. (참고 : 가변 길이 배열 은으로 할당 된 배열 이 아닌 특정 기능입니다 malloc(3).) 그렇지 않으면 표현식 유형 만 계산되고 컴파일시 유형 이 계산됩니다.


33

sizeof컴파일 타임 내장 연산자이며 함수 가 아닙니다 . 괄호없이 사용할 수있는 경우 매우 분명합니다.

(sizeof x)  //this also works

1
그러나 이것이 어떻게 질문에 대한 답입니까?
Sebastian Mach

5
@phresnel : 이것은 sizeof가 "이상하다"는 것을 분명히하기위한 것이며 정상적인 기능의 규칙에 종속되지 않습니다. (-) 나는 (+)와 같은 일반적인 런타임 사업자와 혼동을 제거 어쨌든 게시물을 편집
hugomg

sizeof연산자는 없습니다 만 이것을 알아 내기 위해 그것을 VLA를 제공해야 컴파일 시간 연산자.
paxdiablo

21

노트

이 답변은 복제본에서 병합되어 늦은 날짜를 설명합니다.

기발한

가변 길이 배열을 제외하고 sizeof 는 인수를 평가하지 않습니다. 우리는 C99 표준 초안의 6.5.3.4 운영자의 크기 2 문단 에서 이것을 볼 수 있습니다 .

sizeof 연산자는 피연산자의 크기 (바이트)를 산출하며 표현식 또는 유형의 괄호로 묶은 이름 일 수 있습니다. 크기는 피연산자의 유형에 따라 결정됩니다. 결과는 정수입니다. 피연산자의 유형이 가변 길이 배열 유형 인 경우 피연산자가 평가됩니다. 그렇지 않으면 피연산자가 평가되지 않고 결과는 정수 상수입니다.

주석 ( now removed )은 런타임에 이와 같은 것이 평가되는지 여부를 물었습니다.

sizeof( char[x++]  ) ;

그리고 실제로는 다음과 같이 작동 할 것입니다 ( 모두 라이브 참조 ).

sizeof( char[func()]  ) ;

둘 다 가변 길이 배열이기 때문입니다. 비록 어느 쪽에도 실용적이지는 않다.

가변 길이 배열은 C99 표준 섹션 6.7.5.2 배열 선언자 단락 4 에서 다룹니다 .

[...] 크기가 정수 상수 표현식이고 요소 유형에 알려진 상수 크기가있는 경우 배열 유형은 가변 길이 배열 유형이 아닙니다. 그렇지 않으면 배열 유형은 가변 길이 배열 유형입니다.

최신 정보

C11에서 VLA 경우에 대한 답변이 변경되며, 어떤 경우에는 크기 표현의 평가 여부가 지정되지 않습니다. 6.7.6.2 배열 선언자 섹션에서 :

[...] 크기식이 sizeof 연산자의 피연산자의 일부이고 크기 식의 값을 변경해도 연산자 결과에 영향을 미치지 않는 경우 크기 식의 평가 여부는 지정되지 않습니다.

예를 들어 다음과 같은 경우 ( 실제 참조 ) :

sizeof( int (*)[x++] )

1
여기서 기억해야 할 중요한 점은 대부분의 경우 sizeof사실상 매크로라는 것입니다. 코드를 만들지는 않지만 예상 값을 미리 계산하여 코드에 직접 입금합니다. 참고이는 것을 유일한 C99까지의 동작은, VBAs는 (내가 실제로,이 대답 때까지 들어 보지 믿거 나 말거나 않을 것입니다!) 존재하지 않는 것처럼
콜리 Brigman

표현식의 값 과의 새로운 값을 결정하는 것 이외의 다른 방법으로 sizeof (char[x++]);의 값을 사용하는 방법은 둘 다 해당 연산자에 정상입니까? xx++x
supercat

@alk ... 어, 그래, 물론 'VLA'를 의미했다 :) Shafik-왜 런타임에 평가할까요? 내가 말했듯이, 나는 VLA를 본 적이 없지만 컴파일 시점에 그 유형이 모두 알려져 있습니까?
Corley Brigman

@CorleyBrigman Snappy 답변은 표준에 따르면 b / c 일 것이지만 이유는 b / c이므로 컴파일 타임에 배열 크기를 알지 못하므로 런타임에 표현식을 평가해야합니다. 블라스 여기에 흥미로운 주제입니다 내가 그들에있는이 게시물 수 있습니다 여기여기 .
Shafik Yaghmour

@Shafik-아, 알았어. 혼란은 내가 char[x++]VLA 라는 것을 몰랐다 . 그것은 char*나의 잘 모르는 눈에 효과적으로 보입니다 .
Corley Brigman

11

sizeof연산자 의 피연산자 가 평가되지 않으므로 다음을 수행 할 수 있습니다.

int f(); //no definition, which means we cannot call it

int main(void) {
        printf("%d", sizeof(f()) );  //no linker error
        return 0;
}

온라인 데모 : http://ideone.com/S8e2Y

즉, 함수 만 f사용하는 경우 함수를 정의 할 필요가 없습니다 sizeof. 이 기술은 C ++에서도 피연산자 sizeof가 평가되지 않으므로 C ++ 템플릿 메타 프로그래밍에 주로 사용 됩니다.

왜 이것이 작동합니까? sizeof연산자가 value 에서 작동하지 않기 때문에 작동 하지만 대신 표현식 유형 에서 작동 합니다. 따라서 당신이 쓸 때 sizeof(f()), 그것은 표현식 의 타입 에서 작동 f()하며 함수의 리턴 타입에 지나지 않습니다 f. 함수가 실제로 실행될 경우 어떤 값을 반환하더라도 반환 유형은 항상 동일합니다.

C ++에서는 다음을 수행 할 수도 있습니다.

struct A
{
  A(); //no definition, which means we cannot create instance!
  int f(); //no definition, which means we cannot call it
};

int main() {
        std::cout << sizeof(A().f())<< std::endl;
        return 0;
}

에, 같은 그러나 그것은 보인다 sizeof, 내가 처음의 인스턴스를 만드는거야 A서면에 의해, A()다음 함수를 호출 f작성하여 인스턴스에를 A().f()하지만, 그런 일이 발생하지 않습니다.

데모 : http://ideone.com/egPMi

다음은 다른 흥미로운 속성을 설명하는 또 다른 주제입니다 sizeof.


10

컴파일 중에는 실행할 수 없습니다. 그래서 ++i/ i++일어나지 않을 것입니다. 또한 sizeof(foo())함수를 실행하지 않고 올바른 유형을 반환합니다.


2
" 컴파일 중에는 실행할 수 없습니다. "무슨 뜻입니까?
curiousguy

1
컴파일은 객체 코드 만 생성합니다 ... 객체 코드는 사용자가 바이너리를 실행할 때만 실행됩니다. 컴파일 시간에 sizeof가 발생하면 i ++가 증가한다고 가정하면 잘못됩니다.
rakesh

" 컴파일 시간에 sizeof가 발생 하면" " sizeof컴파일 시간 상수 표현식이 그대로"입니까?
curiousguy

사전 처리 중에 "#define"이 발생하는 것처럼 컴파일시 sizeof도 비슷하게 발생합니다. 컴파일하는 동안 모든 유형 정보를 사용할 수 있으므로 sizeof가 평가되고 컴파일 및 값이 대체됩니다. @pmg "C99 표준에서"에서 이미 언급했듯이.
rakesh

1
" 는 sizeof는 컴파일시에 일어날 가변 길이 배열이 아닌 뭔가"
curiousguy

0

sizeof컴파일 타임 x++에 실행 되지만 런타임에만 평가할 수 있습니다. 이를 해결하기 위해 C ++ 표준은 피연산자 sizeof가 평가되지 않도록 지시합니다 . C 표준은 다음과 같이 말합니다.

피연산자 [of sizeof] 의 유형이 가변 길이 배열 유형 인 경우 피연산자가 평가됩니다. 그렇지 않으면 피연산자가 평가되지 않고 결과는 정수 상수입니다.


C ++에는 VLA가 없습니다.
LF

-2

sizeof() 연산자는 데이터 유형의 크기 만 제공하며 내부 요소는 평가하지 않습니다.


이것은 거짓이며 sizeof()연산자는 재귀 적으로 작동하며 컨테이너의 모든 요소, 클래스 또는 구조의 멤버 등의 크기를 바이트 단위로 가져옵니다. 전화 sizeof()해 그러나 포인터가있는 포인터의 크기는 포인터의 크기 만 볼 수 없습니다. 다른 주석 작성자가 언급했듯이 컴파일 시간에 모두 발생합니다. 내부 표현식 sizeof()은 평가되지 않습니다.
Tyler Shellberg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.