如何在编程之前了解不同体系结构中C中原始类型的大小

时间:2015-02-12 05:20:46

标签: c computer-architecture

我们大学有两种远程系统;我们可以远程连接它们并工作。我在其中一个系统上写了一个C程序,其中void指针的大小和size_t变量的大小是8个字节。但是当我连接到其他系统时,我的程序开始以不同的方式工作。由于这两个系统之间的架构差异,我浪费了太多时间进行调试,并最终发现它正在发生。

我的问题是:

  

原始类型的大小取决于哪些因素?

     

在开始编程之前如何知道基元类型的大小?

     

如何用C编写跨平台代码?

7 个答案:

答案 0 :(得分:1)

通常,处理器中的整数大小取决于ALU在单个周期中可以运行的位数。 对于例如

i)对于8051架构,由于数据总线大小为8位,所有8051编译器指定整数大小为8位。

ii)对于32位ARM架构,因为数据总线是8位宽,整数大小是32位。

您应该始终参考编译器文档以获取正确的数据类型大小。

几乎所有编译都将其名称/版本声明为预定义宏,您可以在头文件中使用它们,如下所示:

#ifedef COMPILER_1

typedef char   S8
typedef int    S16
typedef long   S32
      :
      :

#else COPILER_2

typedef int    S32
typedef long   S64
      :
      :
#endif

然后在你的代码中你可以声明像

这样的变量
S32 Var1;

答案 1 :(得分:1)

问题:

  

原始类型的大小取决于哪些因素?

CPU和编译器。

问题:

  

在开始编程之前如何知道基元类型的大小?

你做不到。但是,您可以编写一个小程序来获取基元类型的大小。

    #include <stdio.h>

    int main()
    {
       printf("Size of short: %zu\n", sizeof(short));
       printf("Size of int: %zu\n", sizeof(int));
       printf("Size of long: %zu\n", sizeof(long));
       printf("Size of long long: %zu\n", sizeof(long long));
       printf("Size of size_t: %zu\n", sizeof(size_t));
       printf("Size of void*: %zu\n", sizeof(void*));
       printf("Size of float: %zu\n", sizeof(float));
       printf("Size of double: %zu\n", sizeof(double));
    }

问题:

  

如何用C编写跨平台代码?

  1. 最小化依赖于基本类型大小的代码。
  2. 在平台之间交换数据时,尽可能使用文本文件来存储持久数据。

答案 2 :(得分:1)

  

如何用C编写跨平台代码?

如果您需要以独立于平台的方式(例如在文件系统上或通过网络)封送数据,那么(至少)这些内容应该是一致的:

  1. 数据类型 - 依靠<stdint.h>的类型。例如,如果您需要一个双字节无符号整数,请使用uint16_t

  2. 数据类型对齐/填充 - 请注意struct中的成员packed/padded的方式。成员的默认对齐方式可能会从一个系统更改为另一个系统,这意味着成员可能处于不同的字节偏移量,具体取决于编译器。在编组数据时,使用__attribute__((packed))(在GCC上)或类似的。

  3. 字节顺序 - 可以按任意顺序存储多字节整数及其字节:Little-endian系统将最低有效字节存储在最低地址/偏移量处,而Big- endian系统从最重要的开始。幸运的是,每个人都同意字节通过网络作为big-endian发送。为此,我们使用htons / ntohs在通过网络连接发送/接收多字节整数时转换字节顺序。

答案 3 :(得分:1)

问题:

  

原始类型的大小取决于什么因素&amp;在开始编程之前如何知道原始类型的大小?

简答:

CPU和编译器。

长答案

要理解原始类型,必须了解原始类型的类型,有两种类型的原始类型:

1。整数类型

整数数据类型的大小范围从至少8位到至少32位。 C99标准将此范围扩展到包括至少64位的整数大小。列出的这些类型的尺寸和范围是最小的;根据您的计算机平台,这些尺寸和范围可能会更大。

  • signed char:范围为-128到127的8位整数值。

  • unsigned char:8位整数值,取值范围为0~255。

  • char:根据您的系统,char数据类型被定义为与signed char或unsigned char数据类型具有相同的范围

  • short int:16位整数值,范围为-32,768到32,767

  • unsigned short int:16位整数值,范围为0到65,535

  • int:32位整数值,范围为-2,147,483,648到2,147,483,647

  • long int:32位整数范围至少为-2,147,483,648到2,147,483,647(根据您的系统,此数据类型可能是64位)

  • unsigned long int:32位整数范围至少为-2,147,483,648到2,147,483,647(根据您的系统,此数据类型可能是64位)

  • long long int:64位整数值,范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。 (此类型不是C89的一部分,但它是C99和GNU C扩展的一部分。)

  • unsigned long long int:64位整数值,范围至少为0到18,446,744,073,709,551,615(此类型不是C89的一部分,但它们都是C99和GNU C扩展的一部分。)

实数类型

  • float:float数据类型是三种浮点类型中最小的一种,如果它们的大小完全不同的话。其最小值存储在FLT_MIN中,不应大于1e-37。其最大值存储在FLT_MAX中,不应小于1e37。

  • double:double数据类型至少与float类型一样大。其最小值存储在DBL_MIN中,其最大值存储在DBL_MAX中。

  • long double:type至少与float类型一样大,并且可能更大。其最小值存储在DBL_MIN中,其最大值存储在DBL_MAX中。 问题:

  

如何用C编写跨平台代码?

跨平台代码有两件事要做:

  1. 使用标准&#39; C&#39;类型,而不是平台特定类型
  2. 仅使用内置的#ifdef编译器标志,不要发明自己的
  3. 尝试重新使用,跨平台&#34; base&#34;库隐藏平台代码
  4. 不要使用第三方&#34;应用程序框架&#34;或&#34;运行时环境&#34;

答案 4 :(得分:0)

Jonathan Leffler在他的评论中基本涵盖了这一点,但从技术上讲,你无法知道跨系统/架构的原始类型有多大。如果系统遵循C标准,那么您知道每种变量类型都有最小字节数,但是您可能会获得超过该值的数据。

例如,如果我正在编写一个使用signed long的程序,我可以可靠地知道我将获得至少4个字节,并且我可以存储最多2,147,483,647的数字;但是,有些系统可能会给我超过4个字节。

不幸的是,开发人员无法提前知道(未经测试)系统将返回多少字节,因此良好的代码应足够动态以解决此问题。

此规则的例外情况包括int8_tint16_tint32_tint64_t及其未签名对应方(uintn_t)。使用这些变量类型,您可以确保 n 位数 - 不多也不少。

答案 5 :(得分:0)

C有一个标准的sizeof()运算符。

答案 6 :(得分:0)

我问这个雇用的每个开发人员的问题。

我的问题是你在做这件事。

struct A {
int X;  // 2 or 4 or 8 bytes
short Y; // 2 bytes
}

在32位计算机上,你得到一个48位的结构,32为int,16为短。

在64位计算机上,你得到的结构是80位长,64位为in,16位是简称。

(是的,我知道,这里可能会发生各种各样的深奥内容,但目标是解决问题,而不是混淆提问者。)

当您尝试使用此结构来读取另一个结构写入的内容时,会出现问题。

您需要一个能够正确编组的结构。

struct A {
long X; // 4 bytes
short Y; // 2 bytes
}

现在,在大多数情况下,双方都会正确地读取和写入数据,除非您使用了标记。

如果要通过线路发送内容,则必须使用char,short,long等。如果不是,那么可以使用int作为int,让编译器弄明白。