C/C++中的固定长度数据类型

72 c c++

我听说数据类型的大小int可能因平台而异.

我的第一个问题是:有人带来一些例子,出了什么问题,当程序假定int是4个字节时,但是在不同的平台上它说2个字节?

我遇到的另一个问题是相关的.我知道人们解决这个问题有一些typedefs,比如你有一个像变量u8,u16,u32-这是保证是8位,16位,32位,不管是什么平台的-我的问题是,这是怎么实现的一般?(我不是指stdint库中的类型- 我手动好奇,如何强制某些类型总是说32位而不管平台?)

BЈо*_*вић 41

我知道人们用一些typedef来解决这个问题,就像你有u8,u16,u32这样的变量 - 保证是8位,16位,32位,无论平台如何

有些平台没有特定大小的类型(例如TI的28xxx,其中char的大小为16位).在这种情况下,不可能有8位类型(除非你真的想要它,但这可能会引入性能损失).

这通常是如何实现的?

通常使用typedef.c99(和c ++ 11)在头文件中这些typedef.所以,只需使用它们.

当程序假设一个int是4个字节时,有人会带来一些例子吗,出了什么问题,但是在另一个平台上它是2个字节?

最好的例子是具有不同类型大小的系统之间的通信.从一个平台向另一个平台发送一组int,其中sizeof(int)在两个平台上是不同的,一个必须非常小心.

此外,在32位平台上保存二进制文件中的int数组,并在64位平台上重新解释它.

  • 在32位平台上的二进制文件中为_saving数组添加+1,并在64位平台上重新解释它. (14认同)

pax*_*blo 22

在C标准的早期迭代中,您通常会创建自己的typedef语句,以确保您获得(例如)16位类型,基于#define传递给编译器的字符串,例如:

gcc -DINT16_IS_LONG ...
Run Code Online (Sandbox Code Playgroud)

如今(C99及以上),有一些特定的类型,例如uint16_t,正好是16位宽的无符号整数.

如果包含stdint.h,则可获得精确的位宽类型,至少是宽度类型,具有给定最小宽度等的最快类型,如中所述C99 7.18 Integer types <stdint.h>.如果实现具有兼容类型,则需要提供这些类型.

同样非常有用的是inttypes.h为这些新类型(printfscanf格式字符串)的格式转换添加了一些其他简洁的功能.

  • 不,如果实现具有兼容类型,则C标准仅_requires_它.例如,如果您在12位DSP上运行,那么它不会_have_提供16位uint16_t.它_may_但它不是强制性的:`7.18.1.1/3:这些类型是可选的.但是,如果实现提供宽度为8,16,32或64位的整数类型,没有填充位,并且(对于具有二进制补码表示的有符号类型),它应定义相应的typedef名称. (5认同)
  • 因此,如果您使用`uint16_t`并且平台不支持它,那么我们可以预期在移植过程中会出现编译错误. (4认同)

Yu *_*Hao 16

对于第一个问题:整数溢出.

对于第二个问题:例如,对于typedef无符号32位整数,在int4字节的平台上,使用:

 typedef unsigned int u32;
Run Code Online (Sandbox Code Playgroud)

int2字节而long4字节的平台上:

typedef unsigned long u32;
Run Code Online (Sandbox Code Playgroud)

这样,您只需修改一个头文件即可使这些类型跨平台.

如果有一些特定于平台的宏,则无需手动修改即可实现:

#if defined(PLAT1)
typedef unsigned int u32;
#elif defined(PLAT2)
typedef unsigned long u32;
#endif
Run Code Online (Sandbox Code Playgroud)

如果stdint.h支持C99 ,则首选.


ste*_*fan 8

首先:不要写那些依赖类型的宽度这样的程序short,int,unsigned int,...

基本上:"如果没有标准保证,就不要依赖宽度".

如果你想要真正独立于平台并将值33000存储为有符号整数,那么你不能只假设它int会保留它.一个int至少具有范围-3276732767-3276832767(取决于那些/二进制补码).这还不够,即使它通常是32位,因此能够存储33000.对于这个值你绝对需要一个>16bit类型,因此你只需选择int32_tint64_t.如果此类型不存在,编译器将告诉您错误,但它不会是一个无声的错误.

第二:C++ 11为固定宽度整数类型提供标准头.这些都不能保证在您的平台上存在,但是当它们存在时,它们保证具有确切的宽度.有关参考,请参阅cppreference.com上的这篇文章.该类型的格式命名int[n]_t,并uint[n]_t在那里n8,16,3264.您需要包含标题<cstdint>.该C头是当然的<stdint.h>.

  • "*首先:永远不要编写依赖于类型宽度的程序.*"所以你说我们不应该依赖于32位宽的"uint32_t"?抽象很好,但最终还是有一个点,你需要做一些假设来实际完成任何事情. (7认同)
  • 你是什​​么意思,"永远不会编写依赖于类型宽度的程序"?类型的宽度直接影响可能值的范围,这在选择要使用的类型时非常重要,特别是对于许多人使用C/C++的编程任务类型.如果您正在编写文件系统或需要在受限内存中存储大量值的任何内容,则需要做出这些决策.有一个原因字符串不存储为无符号long long数组. (6认同)
  • 同意,但是当你编写代码时,而不是当你试图学习如何编写这样的头文件时. (3认同)
  • OP:“_我不是指 stdint 库中的类型 - 我手动好奇,如何强制某种类型总是说 32 位,而不管平台如何??)_”; (2认同)
  • @ legends2k使用标准库获得固定宽度整数类型_is_的正确方法. (2认同)

tha*_*ang 6

通常,当您最大化数字或进行序列化时会出现问题.当有人做出明确的大小假设时,会发生一种不常见的情况.

在第一个场景中:

int x = 32000;
int y = 32000;
int z = x+y;        // can cause overflow for 2 bytes, but not 4
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,

struct header {
int magic;
int w;
int h;
};
Run Code Online (Sandbox Code Playgroud)

然后一个去fwrite:

header h;
// fill in h
fwrite(&h, sizeof(h), 1, fp);

// this is all fine and good until one freads from an architecture with a different int size
Run Code Online (Sandbox Code Playgroud)

在第三种情况中:

int* x = new int[100];
char* buff = (char*)x;


// now try to change the 3rd element of x via buff assuming int size of 2
*((int*)(buff+2*2)) = 100;

// (of course, it's easy to fix this with sizeof(int))
Run Code Online (Sandbox Code Playgroud)

如果您使用的是相对较新的编译器,我会使用uint8_t,int8_t等,以确保类型大小.

在较旧的编译器中,typedef通常基于每个平台定义.例如,有人可能会这样做:

 #ifdef _WIN32
      typedef unsigned char uint8_t;
      typedef unsigned short uint16_t;
      // and so on...
 #endif
Run Code Online (Sandbox Code Playgroud)

通过这种方式,每个平台都会有一个标题,用于定义该平台的细节.

  • +1是第一个提到结构.您还应该了解通过网络发送strct时会发生什么. (2认同)
  • +1简单回答简单代码可能出错 (2认同)

chw*_*arr 5

我手动好奇,如何强制某些类型总是说32位无论平台?

如果您希望(现代)C++程序的编译失败,如果给定的类型不是您期望的宽度,请添加一个static_assert地方.我将这个添加到关于类型宽度的假设的地方.

static_assert(sizeof(int) == 4, "Expected int to be four chars wide but it was not.");
Run Code Online (Sandbox Code Playgroud)

chars 在大多数常用平台上都是8位大,但并非所有平台都以这种方式工作.

  • `sizeof`实际上在`char`s中返回大小,而不是字节.因此,如果你想检查*bits*中的大小,你应该做`sizeof(int)*CHAR_BIT == 32`. (3认同)