C에서 size_t는 무엇입니까?


626

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

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

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

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


11
이러한 옵션이 유일한 옵션 인 int경우 some_size서명 size_t이없는 경우 if 가 사용 됩니다 .
Nate

8
@Nate 맞지 않습니다. POSIX에는 ssize_t 유형이 있지만 실제로 사용할 올바른 유형은 ptrdiff_t입니다.
Steven Stewart-Gallus

2
인텔 ® 64의 저수준 프로그래밍 : C, 어셈블리 및 프로그램 실행에서와 같이 정답은 명확하지 않습니다 . 이 책에서 언급했듯이 인덱스를 사용하는 int i것만으로는 거대한 배열을 다루기에 충분하지 않을 수 있습니다. 따라서 size_t i문제를 일으키지 않는 거대한 배열이 있어도 더 많은 인덱스 를 사용할 수 있습니다. size_t데이터 유형입니다. 일반적으로 a unsigned long int이지만 시스템에 따라 다릅니다.
브루노

답변:


461

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모든 배열 인덱스를 보유하도록 보장 된 유형입니다.


4
"크기를 가져 오거나 반환하는 라이브러리 함수는 크기가 ... size_t"인 것으로 예상합니다. stat ()는 파일 크기에 off_t를 사용하는 것을 제외하고
Draemon

64
@Draemon 그 의견은 근본적인 혼란을 반영합니다. size_t메모리에있는 객체를위한 것입니다. C 표준은 심지어 디스크 나 파일 시스템과 관련이 stat()없거나 off_t(POSIX 정의) 또는 FILE스트림과 관련이 없습니다. 가상 메모리 관리는 크기 요구 사항에 따라 파일 시스템 및 파일 관리와 완전히 다르므로 off_t여기에서는 언급 하지 않습니다.
jw013

3
@ jw013 : 나는 그것을 근본적인 혼란이라고 부르지 않지만 흥미로운 점을 지적합니다. 여전히 인용 된 텍스트에는 "메모리 내 객체의 크기"가 표시되지 않으며 "오프셋"은 저장 위치에 관계없이 크기 유형에 적합한 이름이 아닙니다.
Draemon 2018 년

30
@Draemon 좋은 지적. 이 답변은 Wikipedia를 인용하며,이 경우에는 최고의 설명이 없습니다. C 표준 자체가 훨씬 더 명확합니다. 연산자 size_t의 결과 유형으로 정의합니다 sizeof(7.17p2 about <stddef.h>). 6.5 절에서는 C 표현식의 작동 방식을 정확하게 설명합니다 (6.5.3.4의 경우 sizeof). sizeof디스크 파일 에는 적용 할 수 없기 때문에 (주로 C는 디스크와 파일의 작동 방식을 정의하지 않기 때문에) 혼동 할 여지가 없습니다. 다시 말해, Wikipedia (그리고 실제 C 표준이 아닌 Wikipedia 인용에 대한 답변)를 비난합니다.
jw013

2
@Draemon-또한 "기본 혼동"평가에 동의합니다. C / C ++ 표준을 읽지 않았다면 "객체"가 "객체 지향 프로그래밍"을 의미한다고 생각할 수도 있습니다. OOP 객체는 없지만 아직 객체가있는 C 표준을 읽고 알아보십시오. 대답은 당신을 놀라게 할 수 있습니다!
Heath Hunnicutt

220

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.


8
@ Alok : 두 가지 질문 : 1) 크기는 size_t무엇입니까? 2) 왜 size_t같은 것을 선호해야 unsigned int합니까?
Lazer

2
@Lazer :의 크기는 size_t입니다 sizeof(size_t). C 표준은 SIZE_MAX65535 이상 임을 보증합니다 . 연산자가 size_t리턴 한 유형 sizeof이며 표준 라이브러리에서 사용됩니다 (예 : strlenreturns size_t). Brendan이 말했듯 size_t이와 같을 필요는 없습니다 unsigned int.
Alok Singhal

4
@Lazer-예, size_t부호없는 형식이어야합니다.
Alok Singhal

2
@Celeritas 아니오, 부호없는 유형은 음이 아닌 값만 나타낼 수 있음을 의미합니다. "음수 값을 나타낼 수 없습니다"라고 말했을 것입니다.
Alok Singhal

4
@JasonOster, 2의 보수는 C 표준의 요구 사항이 아닙니다. 의 값이 s2 - s1오버플로 int인 경우 동작이 정의되지 않습니다.
Alok Singhal

73

size_t 모든 배열 색인을 보유 할 수있는 유형입니다.

구현에 따라 다음 중 하나 일 수 있습니다.

unsigned char

unsigned short

unsigned int

unsigned long

unsigned long long

내 컴퓨터 size_t에 어떻게 정의되어 stddef.h있습니까?

typedef unsigned long size_t;

4
확실히 typedef unsigned long size_t컴파일러에 따라 다릅니다. 아니면 항상 그렇게 제안하고 있습니까?
chux-복원 Monica Monica

4
@ chux : 실제로, 한 구현이 그것을 정의한다고해서 모든 것을 의미하지는 않습니다. 적절한 예 : 64 비트 Windows. unsigned long32 비트이고 size_t64 비트입니다.
Tim Čas

2
size_t의 목적은 정확히 무엇입니까? "int mysize_t;"와 같은 변수를 직접 만들 수있는 경우 또는 "long mysize_t"또는 "unsigned long mysize_t". 누군가 나를 위해이 변수를 작성해야하는 이유는 무엇입니까?
midkin

1
@midkin size_t은 변수가 아닙니다. 메모리에서 객체의 크기를 나타내려고 할 때 사용할 수있는 유형입니다.
Arjun Sreedharan

1
그것은 사실이다 size_t, 마찬가지로 64bit를 항상 32 비트 시스템에서 32 비트?
존 우

70

당신이 경험적인 유형이라면 ,

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에서 배열의 최대 크기는 얼마입니까?


1
나는 동일한 환경을 가지고 있지만 GCC의 "-m32"옵션을 전달하여 32 비트로 테스트했습니다. 결과는 "typedef unsigned int size_t"입니다. 이 멋진 명령 @Ciro를 공유해 주셔서 감사합니다. :-)
silvioprog 2016 년

2
문제 자체는 혼란스럽지 않습니다. 많은 질문을하고 많은 답변을하려는 것은 혼란스러운 생각입니다. 이 답변과 Arjun Sreedharan의 답변이 여전히 사람들이 묻고 응답하는 것을 막지 못한다는 것이 놀랍습니다.
biocyberman 2016 년

1
멋진 대답, 실제로 당신을 알려주기 때문에 size_t입니다 적어도 인기있는 리눅스 배포판에.
Andrey Portnoy


19

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


내 질문은 항상 있었다 : sizeof가 존재하지 않으면 size_t가 필요합니까?
Dean P

@DeanP : 아마도 그렇지는 않지만, 같은 인수 유형에 어떤 인수 유형을 사용해야하는지에 대한 질문이있을 것 malloc()입니다. 개인적으로, 나는 형의 인수를 볼 버전이 좋았을 것 int, long그리고 long long예를 구현하는 짧은 유형 등을 홍보하는 일부 구현으로, lmalloc(long n) {return (n < 0 || n > 32767) ? 0 : imalloc(n);}[어떤 플랫폼에서, 호출은하기 imalloc(123)호출하는 것보다 싼 것 lmalloc(123);, 심지어 플랫폼에서 size_t16 비트하는`long` 값에서 계산 된 크기를 할당하고 싶어 코드 ...
supercat

할당자가 처리 할 수있는 값보다 큰 경우 할당 실패에 의존 할 수 있어야합니다.
supercat

11

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 비트로의 마이그레이션에 대한 한 가지 교훈이 있다면, 유형에 필요한 속성을 구체적으로 설명하고 다른 프로그램에서 다른 것을 의미하는 속성을 사용하지 않아야했습니다.


동의 " size_tptrdiff_t64 비트 구현에 넓은 64 비트 보장된다는"등 보장 과장된다. 의 범위 size_t는 주로 구현의 메모리 용량에 의해 결정됩니다. "n 비트 구현"은 기본적으로 정수의 기본 프로세서 너비입니다. 확실히 많은 구현이 비슷한 크기의 메모리와 프로세서 버스 너비를 사용하지만, 스캔 메모리가있는 넓은 기본 정수 또는 많은 메모리가있는 좁은 프로세서가 존재하며이 두 가지 구현 속성을 구분합니다.
chux-복원 Monica Monica

8

size_tint호환되지 않습니다. 예를 들어 64 비트 Linux size_t에서 크기는 64 비트 (즉 sizeof(void*))이지만 int32 비트입니다.

또한 size_t서명되지 않았습니다. 서명 된 버전이 필요한 경우 ssize_t일부 플랫폼에 있으며 예제와 관련이 있습니다.

일반적으로 내가 사용하는 것이 좋습니다 것이 int가장 일반적인 경우에 만 사용 size_t/ ssize_t그것의 특정의 필요 (함께있을 때 mmap(), 예를 들어).


3

일반적으로 0에서 시작하여 위로 올라가는 경우 항상 부호없는 유형을 사용하여 오버플로로 인해 음수 값 상황이되지 않도록하십시오. 배열 경계가 루프의 최대 값보다 작지만 루프 최대 값이 유형의 최대 값보다 큰 경우 음수를 감쌀 수 있고 분할 오류 (SIGSEGV)가 발생할 수 있으므로 이는 매우 중요합니다. ). 따라서 일반적으로 0에서 시작하여 위로 올라가는 루프에는 int를 사용하지 마십시오. 부호없는 것을 사용하십시오.


3
나는 당신의 주장을 받아 들일 수 없습니다. 오버플로 버그가 자동으로 배열 내의 유효한 데이터에 액세스하는 것이 더 낫다고 말합니까?
maf-soft

1
@ maf-soft가 정확합니다. 오류가 감지되지 않으면 프로그램 충돌보다 악화됩니다. 이 답변이 왜 인기를 얻었습니까?
yoyo_fun

배열의 유효한 데이터에 액세스하면 서명되지 않은 유형이 제한 서명 된 유형으로 오버플로되지 않으므로 버그가 아닙니다. 이 논리 녀석은 무엇입니까? 어떤 이유로 든 char을 사용하여 256 개 이상의 요소 배열을 반복한다고 가정 해 봅시다. 부호가 127에서 오버플로되고 128 번째 요소가 sigsegv를 의미하지만 unsigned를 사용하면 의도 한대로 전체 배열을 통과합니다. 다시 int를 사용할 때 배열은 실제로 20 억 요소보다 크지 않으므로 어느 쪽이든 중요하지 않습니다 ...
Purple Ice

1
정수 오버플로가 긍정적이든 부정적이든 상관없이 정수 오버플로가 버그가 아닌 상황을 상상할 수 없습니다. segfault를 얻지 못한다고해서 올바른 행동을하는 것은 아닙니다! 오프셋이 양수인지 음수인지에 관계없이 세그먼테이션 오류가 발생할 수 있습니다. 그것은 모두 메모리 레이아웃에 달려 있습니다. @PurpleIce, 나는 당신 이이 대답과 같은 것을 말하는 것으로 생각하지 않습니다. 당신의 주장은 당신이 그것에 넣고 싶은 가장 큰 값을 보유 할만 큼 큰 데이터 유형을 선택해야한다는 것입니다.
Soren Bjornstad

즉, 루프 인덱스에 대해 부호없는 유형을 의미 적으로 사용하는 것이 좋습니다 . 변수가 음수가 아닌 경우 선택한 유형으로 표시 할 수도 있습니다. 또한 컴파일러가 값이 음수로 끝나는 버그를 발견 할 수는 있지만 GCC는이 특정 실수를 발견하는 데 상당히 끔찍합니다 (한 번은 부호를 -1로 초기화하고 경고를받지 못했습니다). 마찬가지로 size_t는 의미 적으로 배열 인덱스에 적합합니다.
Soren Bjornstad

3

size_t는 부호없는 정수 데이터 유형입니다. GNU C 라이브러리를 사용하는 시스템에서는 부호없는 int 또는 부호없는 long int입니다. size_t는 일반적으로 배열 인덱싱 및 루프 카운팅에 사용됩니다.


1

루프 변수는 일반적으로 0 이상이므로 size_t 또는 부호없는 유형은 루프 변수로 사용되는 것으로 볼 수 있습니다.

size_t 객체를 사용할 때는 산술을 포함하여 모든 컨텍스트에서 음수가 아닌 값만 원하는지 확인해야합니다. 예를 들어, 다음 프로그램은 예상치 못한 결과를 제공합니다.

// C program to demonstrate that size_t or
// any unsigned int type should be used 
// carefully when used in a loop

#include<stdio.h>
int main()
{
const size_t N = 10;
int a[N];

// This is fine
for (size_t n = 0; n < N; ++n)
a[n] = n;

// But reverse cycles are tricky for unsigned 
// types as can lead to infinite loop
for (size_t n = N-1; n >= 0; --n)
printf("%d ", a[n]);
}

Output
Infinite loop and then segmentation fault

1

size_t0과 0보다 큰 정수 값을 할당 할 수있는 부호없는 정수 데이터 유형입니다. 객체 크기의 바이트를 측정하고 sizeof연산자가 반환합니다 . const의 구문 표현 size_t이지만 const프로그램을 실행할 수 없습니다 .

const size_t number;

size_t배열 인덱싱 및 루프 카운팅에 정기적으로 사용됩니다. 컴파일러가 32-bit작동하면 작동합니다 unsigned int. 컴파일러 인 경우 에도 64-bit작동합니다 unsigned long long int. size_t컴파일러 유형 에 따라 최대 크기가 있습니다 .

size_t이미에 정의 <stdio.h>헤더 파일, 그러나 그것은 또한으로 정의 할 수 있습니다 <stddef.h>, <stdlib.h>, <string.h>, <time.h>, <wchar.h>헤더.

  • 예 (포함 const)
#include <stdio.h>

int main()
{
    const size_t value = 200;
    size_t i;
    int arr[value];

    for (i = 0 ; i < value ; ++i)
    {
        arr[i] = i;
    }

    size_t size = sizeof(arr);
    printf("size = %zu\n", size);
}

출력-: size = 800


  • 예 (없이 const)
#include <stdio.h>

int main()
{
    size_t value = 200;
    size_t i;
    int arr[value];

    for (i = 0 ; i < value ; ++i)
    {
        arr[i] = i;
    }

    size_t size = sizeof(arr);
    printf("size = %zu\n", size);
}

출력-: size = 800


-3

나의 이해에서, size_t입니다 unsigned누구의 비트 크기 기본 아키텍처의 포인터를 보유 할 충분한입니다 정수.

그래서:

sizeof(size_t) >= sizeof(void*)

16
사실이 아니다. 포인터 크기가보다 클 수 있습니다 size_t. 몇 가지 예 : x86 리얼 모드의 C 컴파일러는 32 비트 FAR또는 HUGE포인터를 가질 수 있지만 size_t는 여전히 16 비트입니다. 또 다른 예 : Watcom C는 48 비트 폭이지만 확장 size_t되지 않은 확장 메모리를위한 특수한 팻 포인터를 사용했습니다 . 하버드 아키텍처의 임베디드 컨트롤러에서는 서로 다른 주소 공간과 관련이 있기 때문에 상관 관계가 없습니다.
Patrick Schlüter

1
그리고 그 stackoverflow.com/questions/1572099/… 128 비트 포인터와 32 비트를 가진 AS / 400 예제가 더 있습니다size_t
Patrick Schlüter

이것은 명백히 거짓입니다. 그러나 여기에
두겠습니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.