C++ C/C+中的固定长度数据类型+;
我听说,C++ C/C+中的固定长度数据类型+;,c++,c,C++,C,我听说,int等数据类型的大小可能因平台而异 我的第一个问题是:有人能举个例子吗?当程序运行时,出现了什么问题 假设一个int是4个字节,但在另一个平台上是2个字节 我的另一个问题与此有关。我知道人们用一些typedef来解决这个问题, 就像你有像u8,u16,u32这样的变量,不管平台如何,它们都保证为8位、16位、32位——我的问题是,这通常是如何实现的?(我不是指stdint库中的类型-我很好奇,不管平台如何,如何强制某些类型始终是32位的???)在C标准的早期迭代中,您通常会自己编写ty
int
等数据类型的大小可能因平台而异
我的第一个问题是:有人能举个例子吗?当程序运行时,出现了什么问题
假设一个int
是4个字节,但在另一个平台上是2个字节
我的另一个问题与此有关。我知道人们用一些typedef
来解决这个问题,
就像你有像
u8
,u16
,u32
这样的变量,不管平台如何,它们都保证为8位、16位、32位——我的问题是,这通常是如何实现的?(我不是指stdint库中的类型-我很好奇,不管平台如何,如何强制某些类型始终是32位的???)在C标准的早期迭代中,您通常会自己编写typedef
语句,以确保获得(例如)16位类型,基于#定义传递到编译器中的字符串,例如:
gcc -DINT16_IS_LONG ...
如今(C99及以上版本),有一些特定类型,如uint16\u t
,正好是16位宽的无符号整数
如果包含stdint.h
,则可以得到精确的位宽度类型、至少该宽度类型、具有给定最小宽度的最快类型等等,如C99 7.18整数类型
中所述。如果实现具有兼容类型,则需要它们提供这些类型
同样非常有用的是inttypes.h
,它为这些新类型(printf
和scanf
格式字符串)的格式转换添加了一些其他简洁的功能。首先:不要编写依赖于类型宽度的程序,如short
,int
,无符号int
基本上:“如果标准没有保证,就不要依赖宽度”
如果您希望真正独立于平台,并将值33000存储为带符号整数,则不能仅假设int
将保存该值。int
至少具有范围-32767
到32767
或-32768
到32767
(取决于一/二的补码)。这还不够,尽管它通常是32位的,因此能够存储33000。对于该值,您肯定需要一个>16位
类型,因此您只需选择int32\u t
或int64\u t
。如果此类型不存在,编译器将告诉您错误,但这不会是一个无声的错误
第二:C++11为固定宽度整数类型提供了一个标准头。这些都不能保证存在于您的平台上,但当它们存在时,它们保证具有精确的宽度。请参阅以获取参考。类型的命名格式为int[n]\u t
和uint[n]\u t
,其中n
是8
、16
、32
或64
。您需要包括标题
。C
标题当然是
如果类型比您认为的小,那么它可能无法存储您需要存储的值
要创建固定大小的类型,请阅读要支持的平台的文档,然后根据特定平台的#ifdef
定义typedef
s
关于第一个问题:
对于第二个问题:例如,对于typedef
无符号32位整数,在int
为4字节的平台上,使用:
typedef unsigned int u32;
在int
为2字节而long
为4字节的平台上:
typedef unsigned long u32;
这样,您只需要修改一个头文件就可以使类型跨平台
如果存在某些特定于平台的宏,则无需手动修改即可实现:
#if defined(PLAT1)
typedef unsigned int u32;
#elif defined(PLAT2)
typedef unsigned long u32;
#endif
如果支持C99stdint.h
,则首选
我很好奇,一个人怎么能强制某些类型总是说32位,而不管平台是什么
如果你希望(现代)C++程序编译失败,如果给定的类型不是你期望的宽度,那么在某处添加<代码> StistaSytRe>/Cuff>。我会在假设类型宽度的地方加上这个
static_assert(sizeof(int) == 4, "Expected int to be four chars wide but it was not.");
大多数常用平台上的字符都是8位,但并非所有平台都是这样工作的 好吧,第一个例子——类似这样:
int a = 45000; // both a and b
int b = 40000; // does not fit in 2 bytes.
int c = a + b; // overflows on 16bits, but not on 32bits
如果您查看cstdint
头文件,您将发现所有固定大小类型(int8_t
,uint8_t
,等等)是如何定义的,不同体系结构之间唯一不同的是这个头文件。因此,在一种架构上,int16\t
可以是:
typedef int int16_t;
另一方面:
typedef short int16_t;
此外,还有一些其他类型可能很有用,例如:int\u least16\u t
有人能举个例子,当程序假设int是4字节,但在不同的平台上是2字节时,会出现什么问题
假设您将程序设计为读取100000个输入,并使用无符号int
对其进行计数,假设大小为32位(32位无符号int可以计数到4294967295)。如果在具有16位整数(16位无符号整数只能计数到65535)的平台(或编译器)上编译代码,由于容量的原因,该值将超过65535,并表示错误计数。通常,当您将数字最大化或序列化时,会出现此问题。当有人做出明确的尺寸假设时,就会出现一种不太常见的情况
在第一个场景中:
int x = 32000;
int y = 32000;
int z = x+y; // can cause overflow for 2 bytes, but not 4
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))
在第二种情况下
struct header {
int magic;
int w;
int h;
};
然后我们去写:
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
在第三种情况下:
int x = 32000;
int y = 32000;
int z = x+y; // can cause overflow for 2 bytes, but not 4
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))
如果您使用的是相对较新的编译器,我会使用uint8\u t、int8\u t等,以确保类型大小
在较旧的编译器中,typedef通常是基于每个平台定义的。例如,可以执行以下操作:
#ifdef _WIN32
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
// and so on...
#endif
这样,每个平台都会有一个标头,用于定义该平台的细节。编译器