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
    
    如果支持C99
    stdint.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
    
    这样,每个平台都会有一个标头,用于定义该平台的细节。

    编译器