在C89中是否有任何成熟/标准化的方法来使用固定宽度的整数?

时间:2016-10-06 19:33:40

标签: c bit-manipulation c89 ansi-c

一些背景

标题 stdint.h is part of the C standard since C99。它包括typedef,确保为8,16,32和64位长整数,包括有符号和无符号。但是,此标头不是C89标准的一部分,我还没有找到任何简单的方法来确保我的数据类型具有已知长度。

进入实际主题

以下代码是SQLite(用C89编写)如何定义64位整数,但我发现它并不令人信服。也就是说,我认为它无处不在。最糟糕的是,它可能会无声地失败:

/*
** CAPI3REF: 64-Bit Integer Types
** KEYWORDS: sqlite_int64 sqlite_uint64
**
** Because there is no cross-platform way to specify 64-bit integer types
** SQLite includes typedefs for 64-bit signed and unsigned integers.
*/
#ifdef SQLITE_INT64_TYPE
  typedef SQLITE_INT64_TYPE sqlite_int64;
  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
#elif defined(_MSC_VER) || defined(__BORLANDC__)
  typedef __int64 sqlite_int64;
  typedef unsigned __int64 sqlite_uint64;
#else
  typedef long long int sqlite_int64;
  typedef unsigned long long int sqlite_uint64;
#endif
typedef sqlite_int64 sqlite3_int64;
typedef sqlite_uint64 sqlite3_uint64;

所以,这就是我到目前为止所做的事情:

  • 检查" char"数据类型是8位长,因​​为it's not guaranteed to be。如果预处理器变量" CHAR_BIT"不等于8,编译失败
  • 现在" char"保证是8位长,我创建一个包含几个无符号字符数组的结构,它对应于整数中的几个字节。
  • 我写"运营商"我的数据类型的函数。加法,乘法,除法,模数,从/到字符串的转换等

我已经在头文件中抽象了这个过程,这是我能用我所知道做的最好的,但我想知道是否有更直接的方法来实现这一点。

我问,因为我想写一个便携式C库。

2 个答案:

答案 0 :(得分:10)

首先,您应该问自己是否真的需要支持不提供<stdint.h>的实现。它在1999年被标准化,甚至许多C99之前的实现都可能将其作为扩展。

假设你真的需要这个,那么ISO G标准委员会成员Doug Gwyn就为C9x创建了几个新头文件的实现(当时知道了C99),与C89 / C90兼容。标题属于公共领域,应该相当便携。

http://www.lysator.liu.se/(nobg)/c/q8/index.html

(据我了解,名称“q8”没有特别含义;他只是选择它作为一个相当短且独特的搜索词。)

答案 1 :(得分:1)

C中一个相当令人讨厌的整数类型的怪癖源于这样一个事实,即对于至少一个整数大小,许多“现代”实现将具有两个不相容的具有相同位表示的大小的签名类型,同样两个不兼容的无符号类型。最典型的类型是32位“int”和“long”,或64位“long”和“long long”。 “固定大小”类型通常是其中一种标准类型的别名,但实现与哪一种不一致。

虽然编译器过去认为访问某种给定大小的类型可能会影响另一种类型的对象,但标准的作者并未强制要求他们这样做(可能是因为没有必要让人们去做无论如何他们会做的事情,他们无法想象任何理智的编译器作者不这样做;一旦编译器开始这样做,在政治上很难撤销“许可”)。因此,如果有一个库存储32位“int”中的数据而另一个存储32位“long”中的数据,那么确保正确行为的唯一方法就是完全禁用别名分析(可能使用gcc时的最佳选择,或者添加无偿的复制操作(小心gcc不会优化它们然后使用它们的缺席作为破坏代码的借口 - 它有时会从6.2开始)。