【问题标题】:Stdint.h in ANSI C (C89)ANSI C (C89) 中的 Stdint.h
【发布时间】:2020-07-16 14:32:07
【问题描述】:

我最近对从编写 C99 代码转换为编写普通 ANSI C (C89) 产生了兴趣,因为该语言的新特性不值得以 ANSI 编写它的极端可移植性和可靠性C. 我认为从 C99 过渡到 C89 时我会怀念的最大功能之一是 stdint.h 标准库文件;或者我是这么想的。根据this站点,C89标准中没有stdint.h文件,这也是我在Wikipedia上找到的。我想确保情况确实如此,所以我编写了一个最小的测试程序,我预计在 GCC 和 Clang 中提供标志 -ansi-pedantic-errors 时不会编译;

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    printf("The size of an int8_t is %ld.\n",  sizeof(int8_t));
    printf("The size of an int16_t is %ld.\n", sizeof(int16_t));
    printf("The size of an int32_t is %ld.\n", sizeof(int32_t));
    printf("The size of an int64_t is %ld.\n", sizeof(int64_t));

    printf("The size of a uint8_t is %ld.\n",  sizeof(uint8_t));
    printf("The size of a uint16_t is %ld.\n", sizeof(uint16_t));
    printf("The size of a uint32_t is %ld.\n", sizeof(uint32_t));
    printf("The size of a uint64_t is %ld.\n", sizeof(uint64_t));

    return 0;
}

但是,我发现的不是编译器错误,也不是警告,而是编译的程序!由于它在任一编译器上都可以正常工作,因此我假设这不是编译器中的错误。作为参考,输出是人们对 C99 实现的期望:

The size of an int8_t is 1.
The size of an int16_t is 2.
The size of an int32_t is 4.
The size of an int64_t is 8.
The size of a uint8_t is 1.
The size of a uint16_t is 2.
The size of a uint32_t is 4.
The size of a uint64_t is 8.

我对这个“功能”有几个问题。

  • 我应该能够依赖为 C89 程序提供的 stdint.h 标头吗?
  • 如果不是,我必须采取哪些步骤来创建与stdint.h 功能相同的标头?
  • 在 C99 之前的时代,程序员是如何在平台无关的庄园中解决程序中整数大小可靠的问题?

【问题讨论】:

  • > “在 C99 之前的时代,程序员是如何做到的” - 一个扭曲的小 ifdef 迷宫,完全不同。 :-)
  • C89 没有义务阻止您使用系统上出现的任何标头,而不是 stdint.hunistd.hwindows.h 或任何东西别的。但是,如果您要从系统包含目录中删除 stdint.h(不推荐),您的编译器仍将符合 C89,但您的代码将失败。
  • 不要在 C89 中编程。一开始我也讨厌 C99,但它包含了许多需要的语言错误修复。没有隐式int。没有不可靠的整数负除法。没有“结构黑客”。 stdint.h。布尔类型。长长的。 // 厘米。编写名称超过 16 个符号的变量。等等。这是非常基本的东西,在 C89 中被彻底破坏了。
  • 所有这些错误都可以说使 C89 的可移植性降低,因为有太多显而易见的错误,如果你想支持 C89,你必须避开。比如……谁不喜欢使用整数除法?
  • carsonalh,很好奇,为什么要使用 "%ld"sizeof 参数。 那个是不可移植的。 printf("%lu.\n", (unsigned long) sizeof(uint8_t)); 更好。

标签: c libc c89


【解决方案1】:

我应该能够依赖为 C89 程序提供的 stdint.h 标头吗?

没有。您说您选择 C89 是出于可移植性的原因,然后您首先想到的是不可移植的扩展......

如果不是,我必须采取哪些步骤来创建与 stdint.h 功能相同的标头?

在 C99 之前的时间里,程序员是如何在平台无关的庄园中解决在他们的程序中为整数提供可靠大小的问题的?

使用大量宏,例如this answer。如果是 C89,你 typedef 给定平台的 stdint.h 中存在的所有名称。否则,如果是标准 C,则只需包含 stdint.h。

因此,您需要自己的“notstdint.h”,其中包含所有这些,然后您必须将其移植到整数大小不同的每个系统。是的,这使得 C89 的便携性不如标准 C。

【讨论】:

  • 这如何降低 C89 的便携性?如果编写的代码在保证存在时使用stdint.h,则检查一个预定义的宏,指示是否使用备用标头(可以通过构建脚本设置),并且如果这两个条件都不适用,则使用通用整数定义,然后与仅支持 stdint.h 相比,代码将可用于更多种类的编译器。
  • @supercat 因为您必须针对每个目标调整“我的自定义 stdint.h”,并且如果不为每个目标手动输入,就无法知道 C 中所有整数类型的大小。基于limits.h的宏技巧算术可能有一些丑陋的方法。
  • 对于普通目标,可能性并不大。如果uint8_tuint16_tuint32_tuint64_t 中的每一个都映射到标准类型,则unsigned short 必须是 16 位,unsigned long long 必须是 64,并且可以使用 INT_MAX 或LNG_MAX 来确定其中哪一个是 32 位。
【解决方案2】:

在 C89 时代,为微型计算机编写代码时,可以简单地使用:

typedef unsigned char  uint8;
typedef signed char    int8;
typedef unsigned short uint16;
typedef signed short   int16;
typedef unsigned long  uint32;
typedef signed long    int32;

当时,int 可能是 16 位或 32 位,但所有其他类型在可以处理它们的系统(包括所有微型计算机)的常见实现上都具有指示的大小。 16 位系统的编译器将允许从int* 新转换为short* 的指针访问int 类型的对象,因此无需担心int16_t 应该是short 还是@ 987654328@。同样,对于 32 位系统,将允许从 int* 新转换为 long* 的指针访问 int 类型的对象,因此不必担心 int32_t 是否应该是 intlong.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-09
    • 2011-02-14
    • 2010-10-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多