[c] C에서 size_t는 무엇입니까?

size_tC에서 혼동되고 있습니다. sizeof연산자 가 반환한다는 것을 알고 있습니다. 그러나 정확히 무엇입니까? 데이터 타입입니까?

for루프 가 있다고 가정 해 봅시다 .

for(i = 0; i < some_size; i++)

int i;또는 사용해야합니까 size_t i;?



답변

Wikipedia에서 :

1999 ISO C 표준 (C99)에 따르면 size_t16 비트 이상의 부호없는 정수 유형입니다 (섹션 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)를 사용하는 것이 좋습니다 .s1s2

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.hGCC 4.2.

흥미로운 C99 등장

  • malloc필요 size_t가 할당 될 수있는 최대 크기를 결정하므로, 인수로.

    또한로 반환되기 때문에 sizeof모든 배열의 최대 크기를 제한한다고 생각합니다.

    참조 : C에서 배열의 최대 크기는 얼마입니까?


답변

types.h에 대한 맨 페이지 는 다음과 같이 말합니다.

size_t는 부호없는 정수 유형이어야합니다


답변

아무도 그것을 언급하지 않았기 때문에, 언어의 주요 의미 size_tsizeof연산자가 해당 유형의 값을 반환한다는 것입니다. 마찬가지로, ptrdiff_t하나의 포인터를 다른 포인터에서 빼면 해당 유형의 값이 생성된다는 점이 중요합니다. 이를 수용하는 라이브러리 함수는 이러한 유형의 오브젝트가 존재할 수있는 시스템에서 크기가 UINT_MAX를 초과하는 오브젝트에 대해 해당 함수를 사용할 수있게하며, 더 큰 유형의 시스템에서 호출자가 “부호없는 int”보다 큰 값을 전달하지 않아도됩니다. 가능한 모든 물체에 충분합니다.


답변

size_t존재해야하는 이유 와 여기에 도달 한 방법 으로 이동하려면 :

실제로 는 64 비트 구현에서 64 비트 너비, 32 비트 구현에서 32 비트 너비 size_tptrdiff_t이 보장됩니다. 기존 유형을 강제하여 모든 컴파일러에서 레거시 코드를 손상시키지 않고 모든 컴파일러에서 의미 할 수는 없습니다.

size_t또는 ptrdiff_t반드시 동일하지 않습니다 intptr_tuintptr_t. 그들은 아직 사용했다 때 특정 아키텍처에서 달랐다 size_t하고 ptrdiff_t(예 : 16 비트 Windows 등) 80 년대 후반에 표준을 첨가하고, C99 많은 새로운 유형을 추가 할 때 쓸모가되고 있지만, 아직 사라 없습니다. 16 비트 보호 모드의 x86에는 가능한 최대 배열 또는 구조의 크기가 65,536 바이트 일 수있는 세그먼트 화 된 메모리가 있었지만 far포인터는 32 비트, 레지스터보다 넓은 폭이어야했습니다. 이들에, intptr_t32 비트 폭했을 것이다 그러나 size_tptrdiff_t너비가 16 비트이고 레지스터에 맞을 수 있습니다. 그리고 앞으로 어떤 종류의 운영 체제가 작성 될지 누가 알았습니까? 이론적으로 i386 아키텍처는 운영 체제가 실제로 사용하지 않은 48 비트 포인터를 가진 32 비트 세그먼트 화 모델을 제공합니다.

long너무 많은 레거시 코드 long가 정확히 32 비트 너비 라고 가정하기 때문에 메모리 오프셋의 유형이 될 수 없습니다 . 이 가정은 심지어 UNIX 및 Windows API에 내장되었습니다. 불행히도, 다른 많은 레거시 코드는 또한 long포인터, 파일 오프셋, 1970 년 이후 경과 된 초 수 등을 담을 수있을 정도로 넓다고 가정 했습니다. POSIX는 후자 가정을 전자가 아니라 사실로 강제하는 표준화 된 방법을 제공하지만, 이식 가능한 가정은 아닙니다.

int90 년대의 소수의 컴파일러 만이 int64 비트 폭을 만들었 기 때문에 불가능했습니다 . 그런 다음 long32 비트 너비 를 유지하여 정말 이상했습니다 . 다음 표준 개정판은을 ( int를) 초과하는 것이 불법이라고 선언 long했지만 int대부분의 64 비트 시스템에서 여전히 32 비트입니다.

long long int32 비트 시스템에서도 너비가 64 비트 이상으로 만들어지기 때문에 나중에 추가 할 수 없었 습니다.

따라서 새로운 유형이 필요했습니다. 그렇지 않은 경우에도 다른 모든 유형은 배열 또는 객체 내의 오프셋 이외의 것을 의미합니다. 그리고 32 비트에서 64 비트로의 마이그레이션에 대한 한 가지 교훈이 있다면, 유형에 필요한 속성을 구체적으로 설명하고 다른 프로그램에서 다른 것을 의미하는 속성을 사용하지 않아야했습니다.