我听说数据类型的大小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位平台上重新解释它.
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
为这些新类型(printf
和scanf
格式字符串)的格式转换添加了一些其他简洁的功能.
Yu *_*Hao 16
对于第一个问题:整数溢出.
对于第二个问题:例如,对于typedef
无符号32位整数,在int
4字节的平台上,使用:
typedef unsigned int u32;
Run Code Online (Sandbox Code Playgroud)
在int
2字节而long
4字节的平台上:
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 ,则首选.
首先:不要写那些依赖类型的宽度这样的程序short
,int
,unsigned int
,...
基本上:"如果没有标准保证,就不要依赖宽度".
如果你想要真正独立于平台并将值33000存储为有符号整数,那么你不能只假设它int
会保留它.一个int
至少具有范围-32767
来32767
或-32768
到32767
(取决于那些/二进制补码).这还不够,即使它通常是32位,因此能够存储33000.对于这个值你绝对需要一个>16bit
类型,因此你只需选择int32_t
或int64_t
.如果此类型不存在,编译器将告诉您错误,但它不会是一个无声的错误.
第二:C++ 11为固定宽度整数类型提供标准头.这些都不能保证在您的平台上存在,但是当它们存在时,它们保证具有确切的宽度.有关参考,请参阅cppreference.com上的这篇文章.该类型的格式命名int[n]_t
,并uint[n]_t
在那里n
为8
,16
,32
或64
.您需要包含标题<cstdint>
.该C
头是当然的<stdint.h>
.
通常,当您最大化数字或进行序列化时会出现问题.当有人做出明确的大小假设时,会发生一种不常见的情况.
在第一个场景中:
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)
通过这种方式,每个平台都会有一个标题,用于定义该平台的细节.
我手动好奇,如何强制某些类型总是说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位大,但并非所有平台都以这种方式工作.