深入研究系统头文件可能是令人生畏和不愉快的经历。glibc 头文件很容易在您的脑海中造成很多混乱,因为它们在某些情况下包含其他系统头文件,这些头文件会覆盖迄今为止定义的内容。
在 的情况下limits.h
,如果你仔细阅读头文件,你会发现CHAR_BIT
只有在没有 gcc 的情况下编译代码时才会使用 for 的定义,因为这行:
#define CHAR_BIT 8
在if
上面几行的条件内:
/* If we are not using GNU CC we have to define all the symbols ourself.
Otherwise use gcc's definitions (see below). */
#if !defined __GNUC__ || __GNUC__ < 2
因此,如果您使用 gcc 编译代码(很可能是这种情况),CHAR_BIT
则不会使用此定义。这就是为什么您更改它并且您的代码仍然打印旧值的原因。在头文件上向下滚动一点,您可以在使用 GCC 的情况下找到它:
/* Get the compiler's limits.h, which defines almost all the ISO constants.
We put this #include_next outside the double inclusion check because
it should be possible to include this file more than once and still get
the definitions from gcc's header. */
#if defined __GNUC__ && !defined _GCC_LIMITS_H_
/* `_GCC_LIMITS_H_' is what GCC's file defines. */
# include_next <limits.h>
include_next
是 GCC 扩展。您可以在这个问题中了解它的作用:Why would one use #include_next in a project?
简短的回答:它将使用您指定的名称搜索下一个头文件(limits.h
在这种情况下),它将包括 GCC 生成的limits.h
. 在我的系统中,它恰好是/usr/lib/gcc/i486-linux-gnu/4.7/include-fixed/limits.h
.
考虑以下程序:
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("%d\n", CHAR_BIT);
return 0;
}
使用此程序,您可以在 的帮助下找到系统的路径gcc -E
,它为包含的每个文件输出一个特殊行(请参阅http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html)
因为#include <limits.h>
在我命名的这个程序的第 2 行test.c
,运行gcc -E test.c
允许我找到包含的真实文件:
# 2 "test.c" 2
# 1 "/usr/lib/gcc/i486-linux-gnu/4.7/include-fixed/limits.h" 1 3 4
您可以在该文件中找到它:
/* Number of bits in a `char'. */
#undef CHAR_BIT
#define CHAR_BIT __CHAR_BIT__
注意undef
指令:需要覆盖任何可能的先前定义。它是在说:“忘记过去的一切CHAR_BIT
,这是真实的”。__CHAR_BIT__
是一个 gcc 预定义常量。GCC 的在线文档是这样描述的:
__CHAR_BIT__
定义为用于表示 char 数据类型的位数。它的存在是为了使给定数值限制的标准标题正常工作。你不应该直接使用这个宏;相反,包括适当的标题。
你可以用一个简单的程序读取它的值:
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("%d\n", __CHAR_BIT__);
return 0;
}
然后运行gcc -E code.c
。请注意,您不应该直接使用它,正如 gcc 的手册页所述。
显然,如果您更改CHAR_BIT
内部的定义/usr/lib/gcc/i486-linux-gnu/4.7/include-fixed/limits.h
,或系统中的任何等效路径,您将能够在代码中看到此更改。考虑这个简单的程序:
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("%d\n", CHAR_BIT);
return 0;
}
CHAR_BIT
将gcc 中的定义limits.h
(即 中的文件/usr/lib/gcc/i486-linux-gnu/4.7/include-fixed/limits.h
)从9更改__CHAR_BIT__
为 9 将使此代码打印 9。同样,您可以在预处理发生后停止编译过程;你可以用gcc -E
.
如果您使用 gcc 以外的编译器编译代码怎么办?
好吧,就这样吧,默认 ANSI 限制被假定为标准 32 位字。从 ANSI C 标准中的第 5.2.4.2.1 段(整数类型的大小<limits.h>
):
下面给出的值应替换为适用于#if 预处理指令的常量表达式。[...] 它们的实现定义值的大小(绝对值)应等于或大于所示值,且符号相同。
不是位域的最小对象的位数(字节)
CHAR_BIT 8
POSIX 要求兼容的平台具有CHAR_BIT == 8
.
当然,对于没有CHAR_BIT == 8
.glibc 的机器,glibc 的假设可能会出错,但请注意,您必须处于不寻常的架构下并且不使用 gcc 并且您的平台不兼容 POSIX。不太可能。
但是请记住,“定义的实现”意味着编译器编写者选择发生的事情。因此,即使您不使用 进行编译gcc
,您的编译器也有可能定义了某种__CHAR_BIT__
等效项。即使 glibc 不会使用它,您也可以做一些研究并直接使用编译器的定义。这通常是不好的做法 - 您将编写面向特定编译器的代码。
请记住,您永远不应该弄乱系统头文件。当您使用错误且重要的常量(例如CHAR_BIT
. 仅出于教育目的执行此操作,并始终恢复原始文件。