C에서 sizeof 연산자는 2.5m를 통과하면 8 바이트를 반환하지만 1.25m * 2를 통과하면 4 바이트를 반환합니다.
sizeof
운영자가 다음 결과를 생성하는 이유를 이해할 수 없습니다 .
sizeof( 2500000000 ) // => 8 (8 bytes).
... 8을 반환하고 다음을 수행하면
sizeof( 1250000000 * 2 ) // => 4 (4 bytes).
... 8이 아닌 4를 반환합니다 (예상했던 것입니다). 누군가 sizeof
식 (또는 데이터 유형)의 크기를 결정하는 방법 과 내 특정 경우에 이것이 발생하는 이유를 명확히 할 수 있습니까 ?
내 추측으로는 sizeof
연산자가 컴파일 타임 연산자라는 것입니다.
현상금 질문 : 이러한 식을 평가하고 캐스팅없이 예상 출력을 생성 할 수있는 런타임 연산자가 있습니까?
2500000000
에 맞지 int
않으므로 컴파일러는이를 long
(또는 또는 long long
적합한 유형) 으로 올바르게 해석합니다 . 1250000000
그렇습니다 2
. 에 대한 매개 변수는 sizeof
평가되지 않습니다 컴파일러는 아마도 곱셈이에 적합하지 않음을 알 수 있도록 int
하고, 그래서의 크기를 반환합니다 int
.
또한 매개 변수가 평가 된 경우에도 오버플로 (및 정의되지 않은 동작)가 발생할 가능성이 있지만 여전히 4
.
여기:
#include <iostream>
int main()
{
long long x = 1250000000 * 2;
std::cout << x;
}
출력을 추측 할 수 있습니까? 라고 생각하면 2500000000
틀렸을 것입니다. 표현식의 타입 1250000000 * 2
이다 int
피연산자이기 때문에, int
그리고 int
곱셈이 맞지 않는 경우에는 자동적으로 큰 데이터 형식으로 승격되지 않는다.
그래서 여기서 gcc는 그것이라고 말하지만 -1794967296
정의되지 않은 동작이므로 임의의 숫자가 될 수 있습니다. 이 숫자는 int
.
또한 피연산자 중 하나를 예상 유형으로 캐스트하면 (정수가 아닌 결과를 찾고있는 경우 나눌 때 정수를 캐스트하는 것과 유사) 다음과 같이 작동하는 것을 볼 수 있습니다.
#include <iostream>
int main()
{
long long x = (long long)1250000000 * 2;
std::cout << x;
}
올바른 2500000000
.
[편집 : 처음에는 이것이 C와 C ++로 게시 된 것을 알지 못했습니다. 나는 C에 대해서만 대답한다.]
다음 질문에 "어쨌든 런타임에 식이나 변수에 할당 된 메모리 양을 결정할 수 있습니까?"라는 질문에 대답합니다. 정확히는 아닙니다. 문제는 이것이 잘 형성된 질문이 아니라는 것입니다.
(일부 특정 구현 반대) C - 더 - 언어의 "표현"은 실제로 사용하지 않는 모든 메모리를. (특정 구현에서는 CPU 레지스터에 맞는 결과 수 등에 따라 계산을 유지하기 위해 일부 코드 및 / 또는 데이터 메모리가 필요합니다.) 표현식 결과가 변수에 숨겨지지 않으면 단순히 사라집니다 (컴파일러는 저장되지 않은 결과를 계산하기 위해 종종 런타임 코드를 생략합니다.) 언어는 존재한다고 가정하지 않는 것, 즉 표현을위한 저장 공간에 대해 묻는 방법을 제공하지 않습니다.
반면 변수는 스토리지 (메모리)를 차지합니다. 변수 선언은 컴파일러에게 할당 할 스토리지 양을 알려줍니다. 그러나 C99의 가변 길이 배열을 제외하고 필요한 스토리지 는 런타임이 아닌 컴파일 타임에 순전히 결정 됩니다. 이것이 sizeof x
일반적으로 상수 표현식 인 이유 입니다. 컴파일러는 sizeof x
컴파일 시간에 의 값을 결정할 수 있습니다 (실제로는 필수) .
C99의 VLA는 규칙에 대한 특별한 예외입니다.
void f(int n) {
char buf[n];
...
}
필요한 저장소 buf
는 (일반적으로) 컴파일러가 컴파일 타임에 찾을 수있는 sizeof buf
것이 아니므로 컴파일 타임 상수가 아닙니다. 이 경우 buf
실제로는 런타임에 할당되며 크기는 그때만 결정됩니다. 런타임 계산 식도 마찬가지 sizeof buf
입니다 .
그러나 대부분의 경우 모든 것이 컴파일 타임에 미리 크기가 조정되고 런타임에식이 오버플로되면 동작이 정의되지 않거나, 구현에 따라 정의되거나, 유형에 따라 잘 정의됩니다. 25 억에 2를 곱한 부호있는 정수 오버플로는 INT_MAX
27 억을 약간 넘으면 "정의되지 않은 동작"이 발생합니다. 부호없는 정수는 모듈 식 산술을 수행하므로 GF (2 k ) 에서 계산할 수 있습니다 .
일부 계산이 오버플로되지 않도록하려면 런타임에 직접 계산해야합니다. 이것은 다 정밀도 라이브러리 (예 : gmp)를 C로 작성하기 어렵게 만드는 큰 부분입니다. 일반적으로 어셈블리에서 큰 부분을 코딩하고 CPU의 알려진 속성을 활용하는 것이 훨씬 쉽고 빠릅니다. 오버플로 플래그 또는 이중 폭 결과 레지스터 쌍).
Luchian은 이미 대답했습니다. 완성을 위해 ..
C11 표준은 형식 지정에 접미사가없는 정수 리터럴의 형식이 다음과 같이 결정된다고 설명합니다 (C ++ 표준에는 비슷한 줄이 있음).
6.4.4 상수 ( C11 초안 )에서 :
의미론
4 10 진수 상수의 값은 밑이 10으로 계산됩니다. 8 진수 상수, 밑이 8; 16 진수 상수, 밑이 16입니다. 어휘 적으로 첫 번째 숫자가 가장 중요합니다.
5 정수 상수의 유형은 해당 값을 나타낼 수있는 해당 목록 중 첫 번째입니다.
그리고 표는 다음과 같습니다.
소수 상수
int
int long int
long long int
8 진법 또는 16 진법 상수
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
8 진 및 16 진 상수의 경우 부호없는 유형도 가능합니다. 따라서 플랫폼에 따라 위 목록 ( int 또는 long int 또는 long long int )이 먼저 맞는 (순서대로) 정수 리터럴 유형이됩니다.
답을 표현하는 또 다른 방법은 관련이있는 sizeof
것은 표현식의 값이 아니라 유형 이라고 말하는 것입니다 . sizeof
형식 또는 식으로 명시 적으로 제공 할 수있는 형식의 메모리 크기를 반환합니다. 이 경우 컴파일러는 실제로 표현식을 계산 하지 않고 컴파일 타임에이 유형을 계산합니다 (예를 들어 함수를 호출하는 경우 알려진 규칙에 따라 결과 유형은 반환 된 값의 유형입니다).
다른 포스터가 언급했듯이 가변 길이 배열에 대한 예외가 있습니다 (유형 크기는 런타임에만 알려짐).
다른 한마디로 당신은 일반적으로 같은 것을 쓰기 sizeof(type)
또는 sizeof expression
표현식은 L-값입니다. 표현식은 거의 절대로 복잡한 컴퓨팅이 아닙니다 (위의 함수를 호출하는 어리석은 예처럼). 평가되지 않기 때문에 어쨌든 쓸모가 없습니다.
#include <stdio.h>
int main(){
struct Stype {
int a;
} svar;
printf("size=%d\n", sizeof(struct Stype));
printf("size=%d\n", sizeof svar);
printf("size=%d\n", sizeof svar.a);
printf("size=%d\n", sizeof(int));
}
또한 sizeof는 언어 키워드이므로 후행 표현식 앞에 함수 괄호가 필요하지 않습니다 (반환 키워드에 대해 동일한 종류의 규칙이 있음).
후속 질문에는 "연산자"가 없으며 표현식의 "컴파일 시간"크기와 "실행 시간"크기 사이에 차이가 없습니다.
주어진 유형이 원하는 결과를 유지할 수 있는지 알고 싶다면 항상 다음과 같이 시도 할 수 있습니다.
#include <stdio.h>
#include <limits.h>
int main(void) {
int a = 1250000000;
int b = 2;
if ( (INT_MAX / (double) b) > a ) {
printf("int is big enough for %d * %d\n", a, b);
} else {
printf("int is not big enough for %d * %d\n", a, b);
}
if ( (LONG_MAX / (double) b) > a ) {
printf("long is big enough for %d * %d\n", a, b);
} else {
printf("long is not big enough for %d * %d\n", a, b);
}
return 0;
}
종달새만을위한 (약간) 더 일반적인 해결책 :
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
/* 'gssim' is 'get size of signed integral multiplication */
size_t gssim(long long a, long long b);
int same_sign(long long a, long long b);
int main(void) {
printf("size required for 127 * 1 is %zu\n", gssim(127, 1));
printf("size required for 128 * 1 is %zu\n", gssim(128, 1));
printf("size required for 129 * 1 is %zu\n", gssim(129, 1));
printf("size required for 127 * -1 is %zu\n", gssim(127, -1));
printf("size required for 128 * -1 is %zu\n", gssim(128, -1));
printf("size required for 129 * -1 is %zu\n", gssim(129, -1));
printf("size required for 32766 * 1 is %zu\n", gssim(32766, 1));
printf("size required for 32767 * 1 is %zu\n", gssim(32767, 1));
printf("size required for 32768 * 1 is %zu\n", gssim(32768, 1));
printf("size required for -32767 * 1 is %zu\n", gssim(-32767, 1));
printf("size required for -32768 * 1 is %zu\n", gssim(-32768, 1));
printf("size required for -32769 * 1 is %zu\n", gssim(-32769, 1));
printf("size required for 1000000000 * 2 is %zu\n", gssim(1000000000, 2));
printf("size required for 1250000000 * 2 is %zu\n", gssim(1250000000, 2));
return 0;
}
size_t gssim(long long a, long long b) {
size_t ret_size;
if ( same_sign(a, b) ) {
if ( (CHAR_MAX / (long double) b) >= a ) {
ret_size = 1;
} else if ( (SHRT_MAX / (long double) b) >= a ) {
ret_size = sizeof(short);
} else if ( (INT_MAX / (long double) b) >= a ) {
ret_size = sizeof(int);
} else if ( (LONG_MAX / (long double) b) >= a ) {
ret_size = sizeof(long);
} else if ( (LLONG_MAX / (long double) b) >= a ) {
ret_size = sizeof(long long);
} else {
ret_size = 0;
}
} else {
if ( (SCHAR_MIN / (long double) llabs(b)) <= -llabs(a) ) {
ret_size = 1;
} else if ( (SHRT_MIN / (long double) llabs(b)) <= -llabs(a) ) {
ret_size = sizeof(short);
} else if ( (INT_MIN / (long double) llabs(b)) <= -llabs(a) ) {
ret_size = sizeof(int);
} else if ( (LONG_MIN / (long double) llabs(b)) <= -llabs(a) ) {
ret_size = sizeof(long);
} else if ( (LLONG_MIN / (long double) llabs(b)) <= -llabs(a) ) {
ret_size = sizeof(long long);
} else {
ret_size = 0;
}
}
return ret_size;
}
int same_sign(long long a, long long b) {
if ( (a >= 0 && b >= 0) || (a <= 0 && b <= 0) ) {
return 1;
} else {
return 0;
}
}
내 시스템에서 다음을 출력합니다.
size required for 127 * 1 is 1
size required for 128 * 1 is 2
size required for 129 * 1 is 2
size required for 127 * -1 is 1
size required for 128 * -1 is 1
size required for 129 * -1 is 2
size required for 32766 * 1 is 2
size required for 32767 * 1 is 2
size required for 32768 * 1 is 4
size required for -32767 * 1 is 2
size required for -32768 * 1 is 2
size required for -32769 * 1 is 4
size required for 1000000000 * 2 is 4
size required for 1250000000 * 2 is 8
Yes, sizeof() doesn't calculate the memory required for the result of that multiplication.
In the second case both literals : 1250000000
and 2
each requires 4 bytes
of memory, hence sizeof() returns 4
. If one of the values was above 4294967295 (2^32 - 1)
, you would have got 8
.
But i don't know how sizeof() returned 8
for 2500000000
. It returns 4
on my VS2012 compiler
The C11 Draft is here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf You can find the Cx0 draft here: http://c0x.coding-guidelines.com/6.5.3.4.html
In both cases, section 6.5.3.4 is what you are looking for. Basically, your problem boils down to this:
// Example 1:
long long x = 2500000000;
int size = sizeof(x); // returns 8
// Example 2:
int x = 1250000000;
int y = 2;
int size = sizeof(x * y); // returns 4
In example 1, you have a long long
(8 bytes), so it returns 8. In example 2, you have an int * int
which returns an int
, which is 4 bytes (so it returns 4).
To answer your bounty question: Yes and no. sizeof
will not calculate the size needed for the operation you are trying to perform, but it will tell you the size of the results if you perform the operation with the proper labels:
long long x = 1250000000;
int y = 2;
int size = sizeof(x * y); // returns 8
// Alternatively
int size = sizeof(1250000000LL * 2); // returns 8
You have to tell it you are dealing with a large number or it will assume it is dealing with the smallest type it can (which in this case is int
).
The most simple answer in one line is:
sizeof() is a function evaluated at COMPILE TIME who's input is a c type, the value of which is completely ignored
FURTHER DETAIL: ..therefore as 2500000000 is compiled it would have to be stored as a LONG as it is too long to fit in an int, therefore this argument is simply compiled as '(type) long'. However, 1250000000 and 2 both fit in type 'int' therefore that is the type passed to sizeof, since the resulting value is never stored as because the compiler simply is interested in the type, the multiplication is never evaluated.
'program story' 카테고리의 다른 글
Hive는 HDFS에서 파일을 어디에 저장합니까? (0) | 2020.11.17 |
---|---|
Android ViewPager는 현재보기를 가져옵니다. (0) | 2020.11.17 |
교리-관계를 통해 새로운 실체가 발견되었습니다. (0) | 2020.11.17 |
요소를 따라 목록을 하위 목록으로 분할 (0) | 2020.11.17 |
형식 내부에 열거 형 사용-컴파일러 경고 C4482 C ++ (0) | 2020.11.17 |