我正在尝试编写严格的 ISO C89 兼容代码。由于
long long
不是标准的,并且通常在 C99 之前作为编译器扩展实现,因此当我使用它时,编译器应该警告我。但是,当使用 gcc 或 clang 时,使用 int64_t
并扩展为 long long
(使用 32 位编译 -m32
)时不会出现警告。有什么办法让编译器警告我吗?
例如:
/* test.c */
#include <stdint.h>
#include <stdio.h>
int main(void) {
printf("The size of an int64_t is %u.\n", (unsigned)sizeof(int64_t));
return 0;
}
使用 clang 或 gcc 编译:
clang-17 -m32 -std=c89 -Wall -Wextra -Werror -pedantic -pedantic-errors test.c
# or
x86_64-pc-linux-gnu-gcc-13.2.1 -m32 -std=c89 -Wall -Wextra -Werror -pedantic -pedantic-errors test.c
它们不会发出警告或错误,即使
int64_t
实际上是 long long int
的 typedef,因为 clang-17 -m32 -std=c89 -E -dD -Wall -Wextra -Werror -pedantic -pedantic-errors test.c
给了我:
...
#define __INT64_TYPE__ long long int
#define __INT64_FMTd__ "lld"
#define __INT64_FMTi__ "lli"
#define __INT64_C_SUFFIX__ LL
...
并且在
/path/to/clang/17/include/stdint.h
中有
...
#ifdef __INT64_TYPE__
# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/
typedef __INT64_TYPE__ int64_t;
# endif /* __int8_t_defined */
typedef __UINT64_TYPE__ uint64_t;
# undef __int_least64_t
...
但是如果我将上面
int64_t
中的long long
替换为__INT64_TYPE__
或test.c
,编译器会抱怨它。那么为什么 long long
和 uint64_t
之间存在行为差异?
SO 上最相关的问题似乎是 this 和 this,但他们的答案似乎并没有解释为什么使用
-m32
时没有警告。 (在 -m64
模式下,uint64_t
不是问题,因为它扩展为 long
,这是 C89 标准中的)。
代码仍然严格遵循。允许编译器或应用程序具有
#include <header.h>
风格的标头,即使它们不是标准库的一部分。鉴于这些标头中没有任何内容与严格遵守的程序相冲突。它们可能包含自定义类型。标识符 int64_t
等与严格符合 C89 实现中的任何内容都不会冲突。
header.h
(在本例中为stdint.h
)在相应的实现文件中内部执行的操作与编译器无关,除非编译器也负责编译该代码(这不是必需的)。该库必须通过头文件提供 C 接口,但从那里实际库的实现可以是某种 lib 或目标文件格式的交付者。而这甚至不需要用 C 编写。
然而 long long
在 C89 中无效,因为 long
是保留关键字,因此某些第 3 方标头无法提供这样的标识符。
用 gcc 编译
-std=c89 -pedantic-errors
给出:
错误:ISO C90 不支持“long long”[-Wlong-long]
叮当:
错误:未启用 C99 模式时,'long long' 是扩展名 [-Werror,-Wlong-long]
至于
-m32
,这与标准一致性无关。只要 long
至少为 32 位,就符合要求。 32 位应用程序当然也可以支持 64 位类型,尽管 CPU 无法在单个指令中处理这些类型。
如果您仍然坚持出于某种原因阻止
int64_t
进行编译,您可以添加类似以下内容:
#pragma GCC poison int64_t