6

一些背景

自 C99 以来,标头stdint.h 是 C 标准的一部分。它包括确保为 8、16、32 和 64 位长整数的 typedef,包括有符号和无符号的。但是,此标头不是 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 位长,因为不能保证为. 如果预处理器变量“CHAR_BIT”不等于8,编译失败
  • 现在“char”保证为 8 位长,我创建了一个包含几个无符号字符数组的结构,这些字符对应于整数中的几个字节。
  • 我为我的数据类型编写“运算符”函数。加法、乘法、除法、取模、从/到字符串的转换等。

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

我问是因为我想编写一个可移植的 C 库。

4

2 回答 2

11

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

假设您确实需要这个,ISO C 标准委员会的成员 Doug Gwyn 为 C9x(当时已知的 C99)创建了几个新标头的实现,与 C89/C90 兼容。标头在公共领域,应该是可移植的。

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

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

于 2016-10-06T19:51:40.647 回答
2

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

尽管编译器曾经假设对给定大小的一种类型的访问可能会影响另一种类型的对象,但标准的作者并没有强制他们这样做(可能是因为命令人们做他们会做的事情是没有意义的无论如何都要这样做,他们无法想象任何理智的编译器编写者会这样做;一旦编译器开始这样做,在政治上就很难撤销该“许可”)。因此,如果一个库将数据存储在 32 位“int”中,而另一个库从 32 位“long”中读取数据,则确保正确行为的唯一方法是完全禁用别名分析(可能使用 gcc 时最明智的选择)或添加无偿复制操作(注意 gcc 没有

于 2016-10-06T22:21:35.237 回答