uintptr_t 데이터 유형이란 무엇입니까


답변:


198

uintptr_t데이터 포인터를 저장할 수있는 부호없는 정수 유형입니다. 일반적으로 포인터와 크기가 같습니다.

선택적으로 C ++ 11 이상 표준에 정의되어 있습니다.

아키텍처의 포인터 유형을 보유 할 수있는 정수 유형을 원하는 일반적인 이유는 포인터에 정수 특정 연산을 수행하거나 포인터를 정수 "핸들"로 제공하여 포인터 유형을 모호하게하기 위해서입니다.

편집 : Steve Jessop은 당신에게 pedantic 유형에 대한 또 다른 대답에 매우 흥미로운 추가 세부 사항 (내가 훔치지 않을 것입니다)이 있음에 유의 하십시오 :)


53
참고 size_t만하면 가장 큰 개체의 일 크기를 유지하기에 충분하고, 포인터보다 작을 수 있습니다. 이것은 8086 (16 비트 size_t, 32 비트 void*) 과 같은 세그먼트 아키텍처에서 예상됩니다.
MSalters

3
두 포인터의 차이점을 나타 내기 위해 ptrdiff_t. uintptr_t그런 의미가 아닙니다.
jalf

3
@jalf : 차이는 그렇습니다. 그러나 distance 에는 부호없는 유형이 필요합니다.
Drew Dormann

C ++ 11에서도 uintptr_t 정의는 의무적이지 않기 때문에 표준이 아닙니다! cplusplus.com/reference/cstdint (Steve Jessop 답변에서 힌트를 얻음 )
Antonio

2
@MarcusJ는 unsigned int일반적으로 충분히 크지 않습니다. 그러나 충분히 클 수 있습니다. 이 유형은 모든 "가정" 을 제거하기 위해 특별히 존재합니다 .
Drew Dormann

238

첫 번째 질문은 uintptr_tC ++에 없었습니다. <stdint.h>선택적 유형으로 C99에 있습니다. 많은 C ++ 03 컴파일러가 해당 파일을 제공합니다. 또한 C ++ 11에 <cstdint>있으며 여기서 다시 선택 사항이며 정의를 위해 C99를 나타냅니다.

C99에서는 "void에 대한 유효한 포인터를이 유형으로 변환 한 다음 다시 void로 포인터를 변환하여 결과를 원래 포인터와 비교할 수있는 속성이있는 부호없는 정수 유형"으로 정의됩니다.

이것을 말하는 것을 의미합니다. 크기에 대해서는 아무 말도하지 않습니다.

uintptr_t와 같은 크기 일 수 있습니다 void*. 더 클 수도 있습니다. 비록 그러한 C ++ 구현이 어설프게 접근하지만, 더 작을 수도 있습니다. 예를 들어 void*32 비트이지만 24 비트의 가상 주소 공간 만 사용되는 일부 가상 플랫폼에서는 uintptr_t요구 사항을 충족 하는 24 비트 를 가질 수 있습니다 . 구현이 왜 그렇게하는지 모르겠지만 표준에서는 허용합니다.


8
"<stdint.h>"감사합니다. uintptr_t 선언으로 인해 응용 프로그램이 컴파일되지 않았습니다. 그러나 귀하의 의견을 읽으면 "#include <stdint.h>"를 추가하면 이제 작동합니다. 감사!
JavaRunner

2
예를 들어 다른 용도로 정렬 된 메모리할당 하려면 ?
legends2k

4
포인터를 int로 캐스팅하는 또 다른 일반적인 사용 사례는 포인터를 숨기는 불투명 한 핸들을 만드는 것입니다. 이는 객체를 라이브러리에 비공개로 유지하고 응용 프로그램이 액세스하지 못하게하려는 API에서 객체에 대한 참조를 반환하는 데 유용합니다. 그런 다음 응용 프로그램은 API를 사용하여 객체에 대한 작업을 수행해야합니다.
Joel Cunningham

3
@JoelCunningham : 작동하지만 실제로 사용하는 것과 다르지 않습니다 void*. 그러나 변환 된 포인터가 아닌 실제로 정수 핸들 인 것을 사용하도록 변경하려는 경우 가능한 미래 방향에 영향을 미칩니다.
Steve Jessop

2
@CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 일반적인 사용 사례는 일반 데이터에 void *를 기대하는 API에 int 만 전달하는 것입니다. 키 입력을 저장합니다 typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;. 대신 : callback.dataPtr = (void*)val. 다른 한편으로, 당신은 물론 void*그것을 다시 캐스팅해야합니다 int.
Francesco Dondi

19

정확하게 포인터 크기의 부호없는 정수 유형입니다. 예를 들어 모든 비트를 뒤집어서 (이유를 묻지 않는 등) 포인터를 사용하여 비정상적인 작업을 수행해야 할 때마다 uintptr_t일반적인 정수로 캐스트 하고 조작 한 다음 다시 캐스트하십시오.


6
물론 그렇게 할 수는 있지만 정의되지 않은 행동 일 것입니다. 나는 uintptr_t로 캐스트 한 결과로 할 수있는 일 만 변경하지 않고 전달하고 다시 캐스팅하는 것 뿐이라고 생각합니다. 다른 모든 것은 UB입니다.
sleske 2012 년

비트로 연주해야 할 때가 있으며 일반적으로 컴파일러 오류가 발생합니다. 일반적인 예는 특정 비디오 및 성능이 중요한 응용 프로그램에 16 바이트 정렬 메모리를 적용하는 것입니다. stackoverflow.com/questions/227897/…
Cloud

3
@sleske 사실이 아닙니다. 자체 정렬 된 유형을 가진 머신에서, 주소의 2 개의 최하위 비트는 0이 될 것입니다 (주소는 4 또는 8의 배수이므로). 데이터를 압축하기 위해이 취약점을 악용하는 프로그램을 보았습니다 ..
saadtaame

3
@ saadtaame : 나는 이것이 C 표준에 따른 UB임을 지적했다 . 그렇다고 일부 시스템에서는 정의 할 수 없다는 의미는 아닙니다. 컴파일러와 런타임은 표준 C에서 UB 인 특정 동작을 자유롭게 정의 할 수 있습니다. 따라서 모순이 없습니다 :-).
sleske

2
반드시 포인터의 크기 일 필요는 없습니다. 모든 표준 보증은 void*포인터 값을 uintptr_t다시 변환 void*하면 원래 포인터와 동일한 값을 산출 한다는 것입니다. uintptr_t일반적으로와 같은 크기 void*이지만 보장되지는 않으며 변환 된 값의 비트가 특정 의미를 지니고 있다는 보장도 없습니다. 그리고 정보 손실없이 변환 된 포인터 대 함수 값을 보유 할 수 있다는 보장은 없습니다. 마지막으로, 존재한다는 보장은 없습니다.
Keith Thompson

15

"uiintptr_t 데이터 유형은 무엇입니까"부분에 대한 많은 좋은 답변이 이미 있습니다. "어떻게 사용할 수 있습니까?" 이 게시물의 일부입니다.

주로 포인터의 비트 단위 작업에 사용됩니다. C ++에서는 포인터에 대해 비트 단위 연산을 수행 할 수 없습니다. C의 포인터에서 비트 단위 연산을 수행 할 수없는 이유는 무엇입니까?를 참조하십시오 .

따라서 포인터에 대해 비트 단위 연산을 수행하려면 포인터를 unitpr_t 유형으로 캐스팅 한 다음 비트 단위 연산을 수행해야합니다.

다음은 XOR 연결 목록에 저장하기 위해 비트 전용 또는 2 개의 포인터로 작성하는 함수의 예입니다. 우리는 이중 연결 목록처럼 양방향으로 순회 할 수 있지만 각 노드에 2 개의 포인터를 저장하지 않아도됩니다. .

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

1
비트 산술 이외의 객체 카운트 대신 주소를 기반으로 시맨틱을 원할 경우에도 좋습니다.
Alex

4

다른 Necromancer 배지를 얻을 위험을 감수하면서 uintptr_t (또는 intptr_t)에 매우 유용한 사용법을 추가하고 싶습니다. 테스트 가능한 임베디드 코드를 작성하고 있습니다. 나는 다양한 팔과 현재 tensilica 프로세서를 대상으로하는 임베디드 코드를 주로 작성합니다. 이들은 다양한 기본 버스 너비를 가지고 있으며 tensilica는 실제로 너비가 다른 별도의 코드 및 데이터 버스가있는 하버드 아키텍처입니다. 필자는 대부분의 코드에 대해 테스트 중심 개발 스타일을 사용합니다. 즉, 내가 작성한 모든 코드 단위에 대해 단위 테스트를 수행합니다. 실제 대상 하드웨어에 대한 단위 테스트는 번거로우므로 일반적으로 Ceedling 및 GCC를 사용하여 Windows 또는 Linux의 Intel 기반 PC에서 모든 것을 작성합니다. 즉, 많은 임베디드 코드에는 비트 트위들 링 및 주소 조작이 포함됩니다. 내 Intel 컴퓨터의 대부분은 64 비트입니다. 따라서 주소 조작 코드를 테스트하려면 수학을 수행 할 일반화 된 객체가 필요합니다. 따라서 uintptr_t는 대상 하드웨어에 배포하려고 시도하기 전에 기계 독립적으로 코드를 디버깅하는 방법을 제공합니다. 또 다른 문제는 일부 컴파일러 또는 일부 컴파일러의 메모리 모델, 함수 포인터 및 데이터 포인터의 너비가 다릅니다. 이러한 머신에서 컴파일러는 두 클래스 사이의 캐스트를 허용하지 않을 수도 있지만 uintptr_t는 둘 중 하나를 보유 할 수 있어야합니다.


관련이 있는지 확실하지 않습니다 ... "불투명 한 typedef"를 사용해 보셨습니까? Vide : youtube.com/watch?v=jLdSjh8oqmE
shycha

@ sleske C에서 사용할 수 있기를 바랍니다.하지만 stdint.h를 갖는 것이 아무것도 아닌 것보다 낫습니다. (또한 더 강력하게 입력되었지만 대부분의 디버거가 어떤 식 으로든 알아내는 데 도움이되는 열거 형을
원합니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.