[c] size_t 대 uintptr_t

C 표준 size_t은 모든 배열 색인을 보유 할 수있는 유형임을 보증합니다 . 즉, 논리적으로 size_t모든 포인터 유형을 보유 할 수 있어야합니다. Google에서 찾은 일부 사이트에서 이것이 합법적이며 항상 작동해야한다는 것을 읽었습니다.

void *v = malloc(10);
size_t s = (size_t) v;

따라서 C99에서 표준은 intptr_tuintptr_t유형을 도입했으며 서명 된 유형과 서명되지 않은 유형은 포인터를 보유 할 수 있습니다.

uintptr_t p = (size_t) v;

사용 size_t과 의 차이점은 무엇 uintptr_t입니까? 둘 다 부호가 없으며 둘 다 포인터 유형을 보유 할 수 있어야 기능적으로 동일하게 보입니다. 선명도 가 아닌을 사용하는 것보다 uintptr_t더 강력한 이유가 있습니까? 내부 기능으로 만 필드를 처리하는 불투명 한 구조에서이를 수행하지 않을 이유가 있습니까?void *size_t

같은 토큰으로, ptrdiff_t포인터 차이를 보유 할 수있는 부호있는 유형이므로 대부분의 포인터를 보유 할 수 있습니다. 그래서 어떻게 구별 intptr_t됩니까?

이 모든 유형이 기본적으로 동일한 기능의 사소한 다른 버전을 제공하지는 않습니까? 그렇지 않다면 왜? 다른 것으로는 할 수없는 것 중 하나로 무엇을 할 수 없습니까? 그렇다면 왜 C99가 본질적으로 불필요한 두 가지 유형을 언어에 추가 했습니까?

함수 포인터는 현재 문제에 적용되지 않기 때문에 기꺼이 무시하고 싶지만 몰래 의심을 가짐에 따라 함수 포인터는 “올바른”답변의 중심이 될 것입니다.



답변

size_t모든 배열 색인을 보유 할 수있는 유형입니다. 이는 논리적으로 size_t가 모든 포인터 유형을 보유 할 수 있어야 함을 의미합니다.

반드시 그런 것은 아닙니다! 예를 들어, 세그먼트 화 된 16 비트 아키텍처의 시대로 돌아가십시오. 어레이는 단일 세그먼트로 제한 될 수 있으므로 (16 비트 size_t는 가능) 여러 세그먼트를 가질 수 있습니다 (따라서 32 비트 intptr_t유형을 선택해야 함) 세그먼트 및 그 안의 오프셋). 요즘에는 균일하게 처리 할 수있는 세그먼트 화되지 않은 아키텍처에서 이런 일이 이상하게 들리지만, 표준은 “2009 년의 일반적인 것”보다 더 넓은 범위를 충족해야한다는 것을 알고 있습니다!-)


답변

당신의 진술에 관하여 :

“C 표준 size_t은 모든 배열 색인을 보유 할 수있는 유형을 보장합니다 . 이는 논리적으로 size_t모든 포인터 유형을 보유 할 수 있어야 함을 의미합니다 .”

이것은 실제로 오류입니다 (잘못된 추론으로 인한 오해) (a) . 후자는 전자에서 나온다고 생각할 수도 있지만 실제로는 그렇지 않습니다.

포인터와 배열 인덱스는 동일 하지 않습니다 . 배열을 65536 요소로 제한하지만 포인터가 거대한 128 비트 주소 공간으로 모든 값을 지정할 수 있도록하는 적합한 구현을 예상하는 것은 그럴듯합니다.

C99는 size_t변수 의 상한 이 정의되며 SIZE_MAX65535만큼 낮을 수 있다고 명시합니다 (C11에서 변경되지 않은 C99 TR3, 7.18.3 참조). 현대 시스템에서이 범위로 제한되면 포인터가 상당히 제한됩니다.

실제로, 당신은 아마도 당신의 가정이 적용된다는 것을 알게 될 것입니다. 그러나 그것은 표준이 그것을 보장하기 때문이 아닙니다. 실제로 보장 하지 않기 때문입니다.


(a) 이것은 어떤 형태의 개인적인 공격 이 아니며 , 비판적 사고의 맥락에서 왜 당신의 진술이 잘못된 것인지를 진술하는 것입니다. 예를 들어 다음과 같은 추론도 유효하지 않습니다.

모든 강아지가 귀엽다. 이거 귀여워 그러므로 이것은 강아지 여야합니다.

강아지의 귀여움이나 다른 점은 여기에 아무런 관련이 없습니다. 내가 말하고있는 것은 두 가지 사실이 결론으로 ​​이어지지 않는다는 것입니다. 첫 번째 두 문장은 강아지 가 아닌 귀여운 것들의 존재를 허용하기 때문입니다 .

이것은 반드시 두 번째 명령을 요구하지는 않는 첫 번째 진술과 유사합니다.


답변

세그먼트 제한, 이국적인 아키텍처 등의 추론과 관련하여 다른 모든 답변을 스스로 설명하겠습니다.

이름 의 단순한 차이가 올바른 것에 적절한 유형을 사용하기에 충분하지 않습니까?

크기를 저장하는 경우을 사용하십시오 size_t. 포인터를 저장하는 경우을 사용하십시오 intptr_t. 코드를 읽는 사람은 “aha, 이것은 아마도 바이트 단위의 크기”이고 “아, 어떤 이유로 포인터 값이 정수로 저장되어 있습니다”라는 것을 즉시 알게 될 것입니다.

그렇지 않으면 모든 것을 사용할 수 있습니다 unsigned long(또는 여기서는 현대에 unsigned long long). 크기는 모든 것이 아니며, 유형 이름은 프로그램을 설명하는 데 도움이되므로 유용합니다.


답변

가장 큰 배열의 크기가 포인터보다 작을 수 있습니다. 세그먼트 아키텍처를 생각해보십시오. 포인터는 32 비트 일 수 있지만 단일 세그먼트는 64KB (예 : 이전 리얼 모드 8086 아키텍처) 만 처리 할 수 ​​있습니다.

이들은 더 이상 데스크탑 컴퓨터에서 일반적으로 사용되지 않지만 C 표준은 소규모의 특수한 아키텍처도 지원하도록 고안되었습니다. 예를 들어 8 비트 또는 16 비트 CPU로 개발 된 임베디드 시스템이 여전히 있습니다.


답변

코드에서 의도를 더 잘 전달한다고 생각합니다 (그리고 모든 유형 이름에 적용됩니다).

예를 들어, 비록 unsigned shortwchar_t사용, 윈도우 (내 생각)에 같은 크기 wchar_t대신 unsigned short쇼 당신이 아니라 그냥 임의의 수보다 넓은 문자를 저장하는 데 사용할 것이라는 의도를.


답변

앞뒤로보고, 다양한 홀수 볼 아키텍처가 풍경에 흩어져 있음을 상기하면서 기존의 모든 시스템을 래핑하고 미래의 모든 가능한 시스템을 제공하려고합니다.

확실히, 일이 해결되는 방식에는 지금까지 많은 유형이 필요하지 않았습니다.

그러나 다소 일반적인 패러다임 인 LP64에서도 시스템 호출 인터페이스에 size_t 및 ssize_t가 필요했습니다. 풀 64 비트 유형을 사용하는 것이 비싸고 4GB보다 큰 I / O 연산을 펀칭하고 64 비트 포인터가있는 더 제한적인 레거시 또는 미래 시스템을 상상할 수 있습니다.

나는 당신이 궁금해 할 것입니다 : 무엇이 개발되었을 지, 미래에 무엇이 올지. (아마 128 비트 분산 시스템 인터넷 전체 포인터이지만 시스템 호출에서 64 비트 이하, 또는 “레거시”32 비트 제한 일 수도 있습니다. 🙂 레거시 시스템이 새로운 C 컴파일러를 얻을 수있는 이미지. .

또한 당시에 존재했던 것을 살펴보십시오. zillion 286 리얼 모드 메모리 모델 외에도 CDC 60 비트 워드 / 18 비트 포인터 메인 프레임은 어떻습니까? 크레이 시리즈는 어때? 정상적인 ILP64, LP64, LLP64는 신경 쓰지 마십시오. (저는 항상 마이크로 소프트가 LLP64에 집중한다고 생각했습니다. P64 여야했을 것입니다.) 확실히 모든 기반을 다루려는위원회를 상상할 수 있습니다 …


답변

int main(){
  int a[4]={0,1,5,3};
  int a0 = a[0];
  int a1 = *(a+1);
  int a2 = *(2+a);
  int a3 = 3[a];
  return a2;
}

intptr_t가 항상 size_t를 대신해야하며 그 반대의 경우도 마찬가지입니다.