Nice programing

uint_fast32_t보다 uint32_t가 선호되는 이유는 무엇입니까?

nicepro 2020. 10. 9. 12:22
반응형

uint_fast32_t보다 uint32_t가 선호되는 이유는 무엇입니까?


(나는 이것이 일화적인 증거임을 알고 있습니다) uint32_t보다 훨씬 더 널리 퍼져있는 것 같습니다 uint_fast32_t. 그러나 그것은 나에게 반 직관적 인 것 같습니다.

거의 항상 구현 사용을 볼 때 uint32_t실제로 원하는 것은 최대 4,294,967,295 (일반적으로 65,535에서 4,294,967,295 사이 어딘가에 훨씬 낮은 범위) 값을 보유 할 수있는 정수입니다.

그런 다음 사용에 이상한 보인다 uint32_t는 AS, '정확히 32 비트의' 보증이 필요하지 않은, 그리고 '가장 빠른> = 32 비트' 의 보장은 uint_fast32_t정확히 잘 생각이 될 것으로 보인다. 또한 일반적으로 구현되지만 uint32_t실제로 존재한다는 보장은 없습니다.

그렇다면 왜 uint32_t선호 될까요? 단순히 더 잘 알려져 있습니까 아니면 다른 것에 비해 기술적 이점이 있습니까?


uint32_t지원하는 모든 플랫폼에서 거의 동일한 속성을 갖도록 보장됩니다. 1

uint_fast32_t 비교시 서로 다른 시스템에서 작동하는 방식에 대한 보장이 거의 없습니다.

uint_fast32_t크기가 다른 플랫폼으로 전환하는 경우 사용하는 모든 코드를 uint_fast32_t다시 테스트하고 유효성을 검사해야합니다. 모든 안정성 가정은 창 밖으로 나올 것입니다. 전체 시스템은 다르게 작동합니다.

코드를 작성할 때, 당신도 없을 수 있습니다 액세스 A와 uint_fast32_t크기가 32 비트되지 않습니다 시스템.

uint32_t 다르게 작동하지 않습니다 (각주 참조).

속도보다 정확성이 더 중요합니다. 따라서 조기 정확성은 조기 최적화보다 더 나은 계획입니다.

uint_fast32_t64 비트 이상인 시스템에 대한 코드를 작성 하는 경우 두 경우 모두 코드를 테스트하여 사용할 수 있습니다. 필요와 기회를 제외하고 그렇게하는 것은 나쁜 계획입니다.

마지막으로, uint_fast32_t임의의 시간 동안 저장하거나 인스턴스 수 uint32를 저장하면 단순히 캐시 크기 문제와 메모리 대역폭으로 인해 속도가 느려질 수 있습니다 . 오늘날의 컴퓨터는 CPU 바운드보다 메모리 바운드가 훨씬 더 많으며 uint_fast32_t격리 상태에서는 더 빠를 수 있지만 메모리 오버 헤드를 고려한 후에는 그렇지 않습니다.


1 @chux가 주석에서 언급했듯이 unsigned이보다 크면 uint32_t산술 uint32_t은 일반적인 정수 승격을 거치고 그렇지 않은 경우 uint32_t. 이로 인해 버그가 발생할 수 있습니다. 완벽한 것은 없습니다.


왜 많은 사람들이 uint32_t대신 사용 uint32_fast_t합니까?

참고 : 잘못된 이름 uint32_fast_tuint_fast32_t.

uint32_t보다 엄격한 사양을 가지고 uint_fast32_t있으므로보다 일관된 기능을 제공합니다.


uint32_t 장점 :

  • 다양한 알고리즘이이 유형을 지정합니다. IMO-사용하는 가장 좋은 이유.
  • 정확한 너비와 범위가 알려져 있습니다.
  • 이 유형의 어레이는 낭비가 없습니다.
  • 오버플로가있는 부호없는 정수 수학이 더 예측 가능합니다.
  • 다른 언어의 32 비트 유형의 범위 및 수학에서 더 가깝게 일치합니다.
  • 패딩되지 않았습니다.

uint32_t 단점 :

  • 항상 사용할 수있는 것은 아닙니다 (그러나 2018 년에는 드뭅니다).
    예 : 8 / 16 / 32- 비트 정수 (9 / 1018 / 부족 플랫폼 36 비트, 기타 ).
    예 : 2가 아닌 보수를 사용하는 플랫폼. 오래된 2200

uint_fast32_t 장점 :

  • 항상 사용 가능합니다.
    이렇게 하면 새 플랫폼과 이전 플랫폼 모두 항상 빠른 / 최소 유형을 사용할 수 있습니다.
  • 32 비트 범위를 지원하는 "가장 빠른" 유형.

uint_fast32_t 단점 :

  • 범위는 최소한으로 알려져 있습니다. 예를 들어 64 비트 유형일 수 있습니다.
  • 이 유형의 배열은 메모리에서 낭비 일 수 있습니다.
  • 모든 답변 (처음에는 내 것), 게시물 및 댓글에 잘못된 이름이 사용되었습니다 uint32_fast_t. 많은 사람들이이 유형을 필요로하지 않고 사용하는 것 같습니다. 우리는 올바른 이름도 사용하지 않았습니다!
  • 패딩 가능-(희귀).
  • 일부 경우에는 "가장 빠른"유형이 실제로 다른 유형일 수 있습니다. 따라서 uint_fast32_t1 차 근사치입니다.

결국 가장 좋은 것은 코딩 목표에 달려 있습니다. 매우 넓은 이식성 또는 일부 틈새 성능 기능을위한 코딩이 아니라면 uint32_t.


이러한 유형을 사용할 때 또 다른 문제가 있습니다. int/unsigned

아마도 uint_fastN_t적어도 순위는 unsigned. 이것은 지정되지 않았지만 특정하고 테스트 가능한 조건입니다.

따라서, uintN_t보다 많은 가능성 uint_fastN_t을 좁게 unsigned. 이것은 uintN_t수학 을 사용하는 코드가 uint_fastN_t이식성에 관한 것보다 정수 승진의 대상이 될 가능성이 더 높다는 것을 의미 합니다.

이 문제 : uint_fastN_t선택 수학 연산으로 이식성 이점 .


int32_t대신 에 대한 참고 사항 int_fast32_t: 희귀 한 컴퓨터에서는 INT_FAST32_MIN-2,147,483,648이 아닌 -2,147,483,647 수 있습니다. 더 큰 요점 (u)intN_t은 유형이 엄격하게 지정되어 이식 가능한 코드로 이어진다는 것입니다.


왜 많은 사람들이 uint32_t대신 사용 uint32_fast_t합니까?

어리석은 대답 :

  • 표준 유형은 없으며 uint32_fast_t올바른 철자는 다음과 같습니다 uint_fast32_t.

실용적인 대답 :

  • 많은 사람들이 실제로 사용 uint32_t하거나 int32_t정확한 의미를 위해 산술 ( uint32_t) 또는 2의 보수 표현 ( int32_t) 을 부호없는 랩 어라운드로 정확히 32 비트를 사용 합니다. xxx_fast32_t유형이 크고 포장 배열과 구조에 바이너리 파일, 사용에 가게에 따라서 적절하지, 또는 네트워크를 통해 보낼 수 있습니다. 또한 더 빠르지 않을 수도 있습니다.

실용적인 대답 :

  • 많은 사람들 uint_fast32_t이 댓글과 답변에서 보여준 것처럼 에 대해 알지 못합니다 (또는 단순히 신경 쓰지 않습니다). unsigned int많은 현재 아키텍처에는 여전히 16 비트 int가 있고 일부 희귀 박물관 샘플에는 32보다 작은 다른 이상한 int 크기.

UX 답변 :

  • 아마도보다 빠른 있지만 uint32_t, uint_fast32_t느린 사용하는 것입니다 : 그것은 특히 C 문서에서 철자와 의미를 찾는를 차지, 입력 오래 걸립니다 ;-)

우아함이 중요합니다 (분명히 의견 기반) :

  • uint32_t많은 프로그래머가 자신의 유형 u32이나 uint32유형 을 정의하는 것을 선호 할만큼 나쁘게 보입니다. 이 관점에서 uint_fast32_t보면 수리 할 수 ​​없을 정도로 서투른 것처럼 보입니다. 친구들 uint_least32_t함께 벤치에 앉아있는 것은 놀라운 일이 아닙니다 .

한 가지 이유는 unsigned int특별한 typedef가 필요하지 않거나 무언가를 포함 할 필요없이 이미 "가장 빠르다"는 것입니다. 따라서 빠르게 필요하면 기본 int또는 unsigned int유형을 사용하십시오 .
표준은 그것이 가장 빠르다는 것을 명시 적으로 보장하지는 않지만, 3.9.1에서 "Plain int는 실행 환경의 아키텍처에서 제안한 자연적인 크기를 가짐" 을 명시 하여 간접적으로 그렇게합니다 . 즉, (또는 서명되지 않은 대응 물) 프로세서가 가장 편한 것입니다.int

물론 이제 어떤 크기 unsigned int될지 모릅니다. 당신은 그것이 적어도 그것 만큼 크다는 것을 알고있을뿐입니다 short(그리고 나는 그것이 short적어도 16 비트 되어야 한다는 것을 기억하는 것 같습니다 . 비록 지금은 표준에서 그것을 찾을 수 없습니다!). 일반적으로 단순히 4 바이트 일 뿐이지 만 이론적으로는 더 클 수도 있고 극단적 인 경우에는 더 작을 수도 있습니다 ( 개인적으로 1980 년대 8 비트 컴퓨터에서도 이런 아키텍처를 접한 적이 없었지만). .. 아마도 내가 치매로 고통받는 것을 아는 일부 마이크로 컨트롤러 int 는 당시 16 비트 였을 것입니다.)

C ++ 표준은 <cstdint>유형이 무엇인지 또는 무엇을 보장하는지 지정하는 데 신경 쓰지 않고 "C에서와 동일"이라고 만 언급합니다.

uint32_t, C 표준에 따라, 보장 정확히 32 비트를 얻을. 다르지도 않고 패딩 비트도 없습니다. 때로는 이것이 정확히 필요한 것이므로 매우 가치가 있습니다.

uint_least32_t크기가 무엇이든간에 32 비트보다 작을 수는 없지만 더 클 수 있음을 보장합니다. 때로는 정확한 witdh 또는 "상관 안 함"보다 훨씬 드물게 이것이 원하는 것입니다.

마지막으로 uint_fast32_t의도 문서화 목적을 제외하고는 내 의견 으로 는 다소 불필요합니다. C 표준은 "보통 가장 빠른 정수 유형을 지정" ( "보통"이라는 단어에 유의)을 명시하고 모든 목적에 대해 가장 빠를 필요는 없음을 명시 적으로 언급합니다. 즉, uint_fast32_t단지와 거의 같다 uint_least32_t없다, 이는 일반적으로 가장 빠른 너무 만 더 주어진 보장한다 (하지만 보증 어느 쪽이든).

대부분의 경우 정확한 크기에 신경 쓰지 않거나 정확히 32 (또는 64, 때로는 16) 비트를 원하기 때문에 unsigned int어쨌든 "관심 없음" 유형이 가장 빠르기 uint_fast32_t때문에 그렇지 않은 이유 설명됩니다. 자주 사용되는.


나는 범위에 uint32_t사용되는 증거를 보지 못했습니다 . 대신, 그 대부분의 시간을 내가 한을 사용, 그것은 보장 빙 둘러 시프트 의미와 함께, 다양한 알고리즘의 데이터 정확히 4 옥텟을 유지하는 것입니다!uint32_t

uint32_t대신 사용할 다른 이유도 있습니다 uint_fast32_t. 종종 안정적인 ABI를 제공하기 때문입니다. 또한 메모리 사용량을 정확하게 알 수 있습니다. 속도 이득에서 일한다 무엇 이건이 매우 오프셋은 uint_fast32_t, 때마다 그 유형의 구별이 될 것입니다 uint32_t.

값이 65536 미만이면 이미 편리한 유형이 있으며 호출됩니다 unsigned int( unsigned short최소한 해당 범위도 있어야하지만 unsigned int기본 단어 크기 임). 값이 4294967296 미만이면라는 또 다른 유형이 unsigned long있습니다.


그리고 마지막으로 uint_fast32_t입력하는 것이 귀찮고 길고 잘못 입력하기 쉽기 때문에 사람들은 사용하지 않습니다 .


몇 가지 이유.

  1. 많은 사람들은 '빠른'유형이 존재한다는 것을 모릅니다.
  2. 입력하는 것이 더 장황합니다.
  3. 유형의 실제 크기를 모르는 경우 프로그램 동작에 대해 추론하기가 더 어렵습니다.
  4. 표준은 실제로 가장 빠르게 고정되지 않으며 실제로 어떤 유형이 실제로 가장 빠른지도 컨텍스트에 따라 달라질 수 있습니다.
  5. 나는 플랫폼 개발자가 플랫폼을 정의 할 때 이러한 유형의 크기를 고려한다는 증거를 보지 못했습니다. 예를 들어 x86-64 Linux에서 "fast"유형은 x86-64가 32 비트 값에 대한 빠른 작업을위한 하드웨어 지원을 제공하더라도 모두 64 비트입니다.

요약하면 "빠른"유형은 쓸모없는 쓰레기입니다. 특정 응용 프로그램에 대해 어떤 유형이 가장 빠른지 파악해야하는 경우 컴파일러에서 코드를 벤치마킹해야합니다.


정확성과 코딩의 용이성의 관점 에서, 위에서 많은 사용자가 지적했듯이 더 정확하게 정의 된 크기와 산술적 의미 때문에 특히 uint32_t많은 이점 uint_fast32_t이 있습니다.

아마도 놓친 것은 한 가지 장점uint_fast32_t있다는 것입니다. 더 빠를 수 있고 , 의미있는 방식으로 구체화되지 않았다는 것입니다. 64 비트 시대를 장악 한 대부분의 64 비트 프로세서 (대부분 x86-64 및 Aarch64)는 32 비트 아키텍처에서 발전 했으며 64 비트 모드에서도 빠른 32 비트 기본 작업을 수행합니다. 따라서 해당 플랫폼 uint_fast32_t에서와 동일 uint32_t합니다.

POWER, MIPS64, SPARC와 같은 "또한 실행되는"플랫폼 중 일부가 64 비트 ALU 작업 만 제공하더라도 대부분 의 흥미로운 32 비트 작업은 64 비트 레지스터에서 잘 수행 할 수 있습니다. 하위 32 비트는 원하는 결과를 얻을 수 있습니다 (그리고 모든 주류 플랫폼은 적어도 32 비트를로드 / 저장할 수 있습니다). 왼쪽 시프트가 주요 문제이지만 컴파일러의 값 / 범위 추적 최적화를 통해 많은 경우에 최적화 될 수 있습니다.

나는 때때로 약간 느린 왼쪽 시프트 또는 32x32-> 64 곱셈이 그러한 값에 대한 메모리 사용의 두 배 를 능가 할 것이라고 의심합니다 .

마지막으로, 트레이드 오프는 대체로 "메모리 사용 및 벡터화 잠재력"(에 찬성 uint32_t) 대 명령 수 / 속도 (에 찬성 uint_fast32_t) 로 특징 지워졌지만 나에게는 명확하지 않습니다. 예, 일부 플랫폼에서는 일부 32 비트 작업에 대한 추가 지침이 필요 하지만 다음과 같은 이유로 몇 가지 지침 저장 해야합니다.

  • 더 작은 유형을 사용하면 컴파일러가 하나의 64 비트 연산을 사용하여 두 개의 32 비트 연산을 수행함으로써 인접한 연산을 영리하게 결합 할 수 있습니다. 이러한 유형의 "가난한 사람의 벡터화"의 예는 드물지 않습니다. 예를 들어, 상수 struct two32{ uint32_t a, b; }raxlike 생성 하는 것은 단일 two32{1, 2} 로 최적화 할 수 있지만mov rax, 0x20001 64 비트 버전에는 두 가지 명령이 필요합니다. 원칙적으로 이것은 인접한 산술 연산 (동일한 연산, 다른 피연산자)에서도 가능해야하지만 실제로는 보지 못했습니다.
  • "메모리 사용"이 낮 으면 메모리 또는 캐시 풋 프린트가 문제가되지 않더라도 종종 명령어가 줄어 듭니다.이 유형의 모든 유형 구조 또는 배열이 복사되기 때문에 복사 된 레지스터 당 비용이 두 배가됩니다.
  • 더 작은 데이터 유형은 종종 데이터 구조 데이터를 레지스터에 효율적으로 압축하는 SysV ABI와 같은 더 나은 최신 호출 규칙을 활용합니다. 예를 들어 registers에서 최대 16 바이트 구조를 반환 할 수 있습니다 rdx:rax. 4 개의 uint32_t값 (상수에서 초기화 됨)이있는 구조를 반환하는 함수의 경우 다음과 같이 변환됩니다.

    ret_constant32():
        movabs  rax, 8589934593
        movabs  rdx, 17179869187
        ret
    

    64 비트 uint_fast32_t4 개인 동일한 구조 는 동일한 작업을 수행하기 위해 레지스터 이동과 메모리에 4 개의 저장소 가 필요합니다 (호출자는 반환 후 메모리에서 값을 다시 읽어야합니다).

    ret_constant64():
        mov     rax, rdi
        mov     QWORD PTR [rdi], 1
        mov     QWORD PTR [rdi+8], 2
        mov     QWORD PTR [rdi+16], 3
        mov     QWORD PTR [rdi+24], 4
        ret
    

    마찬가지로 구조 인수를 전달할 때 32 비트 값은 매개 변수에 사용할 수있는 레지스터에 약 2 배 조밀하게 압축되므로 레지스터 인수가 부족하여 스택 1 로 넘쳐 야 할 가능성이 줄어 듭니다 .

  • uint_fast32_t"속도가 중요한"장소 에 사용 하기로 선택하더라도 고정 된 크기 유형이 필요한 장소도 있습니다. 예를 들어 외부 출력, 외부 입력, ABI의 일부로, 특정 레이아웃이 필요한 구조의 일부로 또는 uint32_t메모리 공간을 절약하기 위해 값의 대규모 집계에 현명하게 사용 하기 때문에 값을 전달할 때 . 당신의 장소에서 uint_fast32_t와``uint32_t` 유형은 인터페이스에 필요, 당신은 (개발의 복잡성에 추가), 불필요한 기호 확장 또는 다른 크기 불일치 관련 코드를 찾을 수 있습니다. 컴파일러는 많은 경우에 이것을 최적화하는 데 OK 작업을 수행하지만 다른 크기의 유형을 혼합 할 때 최적화 된 출력에서 ​​이것을 보는 것은 여전히 ​​드문 일이 아닙니다.

위의 일부 예제와 godbolt에서 더 많은 것을 재생할 수 있습니다 .


1 명확하게 말하면, 구조를 레지스터에 단단히 묶는 관습이 작은 값에 대해 항상 확실한 승리는 아닙니다. 이는 더 작은 값을 사용하기 전에 "추출"해야 할 수도 있음을 의미합니다. 예를 들어 두 구조체 멤버의 합을 함께 반환하는 간단한 함수 mov rax, rdi; shr rax, 32; add edi, eax는 64 비트 버전의 경우 각 인수가 자체 레지스터를 가져오고 하나의 add또는 lea. 그래도 "통과하면서 구조를 단단히 묶는"디자인이 전체적으로 합리적이라는 점을 받아 들인다면 값이 작을수록이 기능을 더 많이 활용할 수 있습니다.


For practical purposes, uint_fast32_t is completely useless. It's defined incorrectly on the most widespread platform (x86_64), and doesn't really offer any advantages anywhere unless you have a very low-quality compiler. Conceptually, it never makes sense to use the "fast" types in data structures/arrays - any savings you get from the type being more efficient to operate on will be dwarfed by the cost (cache misses, etc.) of increasing the size of your working data set. And for individual local variables (loop counters, temps, etc.) a non-toy compiler can usually just work with a larger type in the generated code if that's more efficient, and only truncate to the nominal size when necessary for correctness (and with signed types, it's never necessary).

The one variant that is theoretically useful is uint_least32_t, for when you need to be able to store any 32-bit value, but want to be portable to machines that lack an exact-size 32-bit type. Practically, speaking, however, that's not something you need to worry about.


To my understanding, int was initially supposed to be a "native" integer type with additional guarantee that it should be at least 16 bits in size - something that was considered "reasonable" size back then.

When 32-bit platforms became more common, we can say that "reasonable" size has changed to 32 bits:

  • Modern Windows uses 32-bit int on all platforms.
  • POSIX guarantees that int is at least 32 bits.
  • C#, Java has type int which is guaranteed to be exactly 32 bits.

But when 64-bit platform became the norm, no one expanded int to be a 64-bit integer because of:

  • Portability: a lot of code depends on int being 32 bit in size.
  • Memory consumption: doubling memory usage for every int might be unreasonable for most cases, as in most cases numbers in use are much smaller than 2 billion.

Now, why would you prefer uint32_t to uint_fast32_t? For the same reason languages, C# and Java always use fixed size integers: programmer does not write code thinking about possible sizes of different types, they write for one platform and test code on that platform. Most of the code implicitly depends on specific sizes of data types. And this is why uint32_t is a better choice for most cases - it does not allow any ambiguity regarding its behavior.

Moreover, is uint_fast32_t really the fastest type on a platform with a size equal or greater to 32 bits? Not really. Consider this code compiler by GCC for x86_64 on Windows:

extern uint64_t get(void);

uint64_t sum(uint64_t value)
{
    return value + get();
}

Generated assembly looks like this:

push   %rbx
sub    $0x20,%rsp
mov    %rcx,%rbx
callq  d <sum+0xd>
add    %rbx,%rax
add    $0x20,%rsp
pop    %rbx
retq

Now if you change get()'s return value to uint_fast32_t (which is 4 bytes on Windows x86_64) you get this:

push   %rbx
sub    $0x20,%rsp
mov    %rcx,%rbx
callq  d <sum+0xd>
mov    %eax,%eax        ; <-- additional instruction
add    %rbx,%rax
add    $0x20,%rsp
pop    %rbx
retq

Notice how generated code is almost the same except for additional mov %eax,%eax instruction after function call which is meant to expand 32-bit value into a 64-bit value.

There is no such issue if you only use 32-bit values, but you will probably be using those with size_t variables (array sizes probably?) and those are 64 bits on x86_64. On Linux uint_fast32_t is 8 bytes, so the situation is different.

Many programmers use int when they need to return small value (let's say in the range [-32,32]). This would work perfectly if int would be platforms native integer size, but since it is not on 64-bit platforms, another type which matches platform native type is a better choice (unless it is frequently used with other integers of smaller size).

Basically, regardless of what standard says, uint_fast32_t is broken on some implementations anyway. If you care about additional instruction generated in some places, you should define your own "native" integer type. Or you can use size_t for this purpose, as it will usually match native size (I am not including old and obscure platforms like 8086, only platforms that can run Windows, Linux etc).


Another sign that shows int was supposed to be a native integer type is "integer promotion rule". Most CPUs can only perform operations on native, so 32 bit CPU usually can only do 32-bit additions, subtractions etc (Intel CPUs are an exception here). Integer types of other sizes are supported only through load and store instructions. For example, the 8-bit value should be loaded with appropriate "load 8-bit signed" or "load 8-bit unsigned" instruction and will expand value to 32 bits after load. Without integer promotion rule C compilers would have to add a little bit more code for expressions that use types smaller than native type. Unfortunately, this does not hold anymore with 64-bit architectures as compilers now have to emit additional instructions in some cases (as was shown above).


In many cases, when an algorithm works on an array of data, the best way to improve performance is to minimize the number of cache misses. The smaller each element, the more of them can fit into the cache. This is why a lot of code is still written to use 32-bit pointers on 64-bit machines: they don’t need anything close to 4 GiB of data, but the cost of making all pointers and offsets need eight bytes instead of four would be substantial.

There are also some ABIs and protocols specified to need exactly 32 bits, for example, IPv4 addresses. That’s what uint32_t really means: use exactly 32 bits, regardless of whether that’s efficient on the CPU or not. These used to be declared as long or unsigned long, which caused a lot of problems during the 64-bit transition. If you just need an unsigned type that holds numbers up to at least 2³²-1, that’s been the definition of unsigned long since the first C standard came out. In practice, though, enough old code assumed that a long could hold any pointer or file offset or timestamp, and enough old code assumed that it was exactly 32 bits wide, that compilers can’t necessarily make long the same as int_fast32_t without breaking too much stuff.

In theory, it would be more future-proof for a program to use uint_least32_t, and maybe even load uint_least32_t elements into a uint_fast32_t variable for calculations. An implementation that had no uint32_t type at all could even declare itself in formal compliance with the standard! (It just wouldn’t be able to compile many existing programs.) In practice, there’s no architecture any more where int, uint32_t, and uint_least32_t are not the same, and no advantage, currently, to the performance of uint_fast32_t. So why overcomplicate things?

Yet look at the reason all the 32_t types needed to exist when we already had long, and you’ll see that those assumptions have blown up in our faces before. Your code might well end up running someday on a machine where exact-width 32-bit calculations are slower than the native word size, and you would have been better off using uint_least32_t for storage and uint_fast32_t for calculation religiously. Or if you’ll cross that bridge when you get to it and just want something simple, there’s unsigned long.


To give a direct answer: I think the real reason why uint32_t is used over uint_fast32_t or uint_least32_t is simply that it is easier to type, and, due to being shorter, much nicer to read: If you make structs with some types, and some of them are uint_fast32_t or similar, then it's often hard to align them nicely with int or bool or other types in C, which are quite short (case in point: char vs. character). I of course cannot back this up with hard data, but the other answers can only guess at the reason as well.

As for technical reasons to prefer uint32_t, I don't think there are any - when you absolutely need an exact 32 bit unsigned int, then this type is your only standardised choice. In almost all other cases, the other variants are technically preferable - specifically, uint_fast32_t if you are concerned about speed, and uint_least32_t if you are concerned about storage space. Using uint32_t in either of these cases risks not being able to compile as the type is not required to exist.

In practise, the uint32_t and related types exist on all current platforms, except some very rare (nowadays) DSPs or joke implementations, so there is little actual risk in using the exact type. Similarly, while you can run into speed penalties with the fixed-width types, they are (on modern cpus) not crippling anymore.

Which is why, I think, the shorter type simply wins out in most cases, due to programmer lazyness.

참고URL : https://stackoverflow.com/questions/46959685/why-would-uint32-t-be-preferred-rather-than-uint-fast32-t

반응형