size_t
C에서 혼동되고 있습니다. sizeof
연산자 가 반환한다는 것을 알고 있습니다. 그러나 정확히 무엇입니까? 데이터 타입입니까?
for
루프 가 있다고 가정 해 봅시다 .
for(i = 0; i < some_size; i++)
int i;
또는 사용해야합니까 size_t i;
?
답변
1999 ISO C 표준 (C99)에 따르면
size_t
16 비트 이상의 부호없는 정수 유형입니다 (섹션 7.17 및 7.18.3 참조).
size_t
에 정의 된 C99 ISO / IEC 9899 표준과 같은 여러 C / C ++ 표준에 의해 정의 된 부호없는 데이터 형식입니다stddef.h
. 1stdlib.h
이 파일의 내부에 포함 된 파일 을 포함하여 추가로 가져올 수 있습니다
stddef.h
.이 유형은 객체의 크기를 나타내는 데 사용됩니다. 크기를 가져 오거나 반환하는 라이브러리 함수는 유형이거나 반환 유형이이라고 예상합니다
size_t
. 또한 가장 자주 사용되는 컴파일러 기반 연산자 sizeof는와 호환되는 상수 값으로 평가해야합니다
size_t
.
함축적으로, size_t
모든 배열 인덱스를 보유하도록 보장 된 유형입니다.
답변
size_t
부호없는 유형입니다. 따라서 음수 값 (<0)을 나타낼 수 없습니다. 당신은 무언가를 세고있을 때 그것을 사용하고 그것이 음수가 될 수 없음을 확신합니다. 예를 들어 문자열의 길이는 0 이상이어야하므로 strlen()
a를 반환합니다 size_t
.
예를 들어, 루프 인덱스가 항상 0보다 크면 size_t
, 또는 기타 서명되지 않은 데이터 유형을 사용하는 것이 좋습니다.
size_t
객체 를 사용할 때 산술을 포함하여 모든 컨텍스트에서 사용되는 음수가 아닌 값을 원하는지 확인해야합니다. 예를 들어, 당신이 가지고 있다고 가정 해 봅시다.
size_t s1 = strlen(str1);
size_t s2 = strlen(str2);
그리고 당신의 길이의 차이를 찾으려 str2
하고 str1
. 당신은 할 수 없습니다 :
int diff = s2 - s1; /* bad */
이는 부호없는 유형으로 계산이 수행되기 때문에 할당 된 값 diff
이 항상 양수가 s2 < s1
되기 때문입니다. 이 경우 사용 사례에 따라 및에 int
(또는 long long
)를 사용하는 것이 좋습니다 .s1
s2
C / POSIX에는을 사용할 수 있거나 사용해야하는 함수가 size_t
있지만, 역사적인 이유는 없습니다. 예를 들어 두 번째 매개 변수 fgets
는 이상적 size_t
이지만 이어야합니다 int
.
답변
size_t
모든 배열 색인을 보유 할 수있는 유형입니다.
구현에 따라 다음 중 하나 일 수 있습니다.
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
내 컴퓨터 size_t
에 어떻게 정의되어 stddef.h
있습니까?
typedef unsigned long size_t;
답변
당신이 경험적인 유형이라면 ,
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Ubuntu 14.04 64 비트 GCC 4.8의 출력 :
typedef long unsigned int size_t;
주 stddef.h
에 따라 GCC가 아닌 glibc에 제공되는 src/gcc/ginclude/stddef.h
GCC 4.2.
흥미로운 C99 등장
-
malloc
필요size_t
가 할당 될 수있는 최대 크기를 결정하므로, 인수로.또한로 반환되기 때문에
sizeof
모든 배열의 최대 크기를 제한한다고 생각합니다.
답변
types.h에 대한 맨 페이지 는 다음과 같이 말합니다.
size_t는 부호없는 정수 유형이어야합니다
답변
아무도 그것을 언급하지 않았기 때문에, 언어의 주요 의미 size_t
는 sizeof
연산자가 해당 유형의 값을 반환한다는 것입니다. 마찬가지로, ptrdiff_t
하나의 포인터를 다른 포인터에서 빼면 해당 유형의 값이 생성된다는 점이 중요합니다. 이를 수용하는 라이브러리 함수는 이러한 유형의 오브젝트가 존재할 수있는 시스템에서 크기가 UINT_MAX를 초과하는 오브젝트에 대해 해당 함수를 사용할 수있게하며, 더 큰 유형의 시스템에서 호출자가 “부호없는 int”보다 큰 값을 전달하지 않아도됩니다. 가능한 모든 물체에 충분합니다.
답변
size_t
존재해야하는 이유 와 여기에 도달 한 방법 으로 이동하려면 :
실제로 는 64 비트 구현에서 64 비트 너비, 32 비트 구현에서 32 비트 너비 size_t
등 ptrdiff_t
이 보장됩니다. 기존 유형을 강제하여 모든 컴파일러에서 레거시 코드를 손상시키지 않고 모든 컴파일러에서 의미 할 수는 없습니다.
size_t
또는 ptrdiff_t
반드시 동일하지 않습니다 intptr_t
나 uintptr_t
. 그들은 아직 사용했다 때 특정 아키텍처에서 달랐다 size_t
하고 ptrdiff_t
(예 : 16 비트 Windows 등) 80 년대 후반에 표준을 첨가하고, C99 많은 새로운 유형을 추가 할 때 쓸모가되고 있지만, 아직 사라 없습니다. 16 비트 보호 모드의 x86에는 가능한 최대 배열 또는 구조의 크기가 65,536 바이트 일 수있는 세그먼트 화 된 메모리가 있었지만 far
포인터는 32 비트, 레지스터보다 넓은 폭이어야했습니다. 이들에, intptr_t
32 비트 폭했을 것이다 그러나 size_t
및ptrdiff_t
너비가 16 비트이고 레지스터에 맞을 수 있습니다. 그리고 앞으로 어떤 종류의 운영 체제가 작성 될지 누가 알았습니까? 이론적으로 i386 아키텍처는 운영 체제가 실제로 사용하지 않은 48 비트 포인터를 가진 32 비트 세그먼트 화 모델을 제공합니다.
long
너무 많은 레거시 코드 long
가 정확히 32 비트 너비 라고 가정하기 때문에 메모리 오프셋의 유형이 될 수 없습니다 . 이 가정은 심지어 UNIX 및 Windows API에 내장되었습니다. 불행히도, 다른 많은 레거시 코드는 또한 long
포인터, 파일 오프셋, 1970 년 이후 경과 된 초 수 등을 담을 수있을 정도로 넓다고 가정 했습니다. POSIX는 후자 가정을 전자가 아니라 사실로 강제하는 표준화 된 방법을 제공하지만, 이식 가능한 가정은 아닙니다.
int
90 년대의 소수의 컴파일러 만이 int
64 비트 폭을 만들었 기 때문에 불가능했습니다 . 그런 다음 long
32 비트 너비 를 유지하여 정말 이상했습니다 . 다음 표준 개정판은을 ( int
를) 초과하는 것이 불법이라고 선언 long
했지만 int
대부분의 64 비트 시스템에서 여전히 32 비트입니다.
long long int
32 비트 시스템에서도 너비가 64 비트 이상으로 만들어지기 때문에 나중에 추가 할 수 없었 습니다.
따라서 새로운 유형이 필요했습니다. 그렇지 않은 경우에도 다른 모든 유형은 배열 또는 객체 내의 오프셋 이외의 것을 의미합니다. 그리고 32 비트에서 64 비트로의 마이그레이션에 대한 한 가지 교훈이 있다면, 유형에 필요한 속성을 구체적으로 설명하고 다른 프로그램에서 다른 것을 의미하는 속성을 사용하지 않아야했습니다.