我正在为地址0x0000有效且包含端口I / O的系统编写C代码。因此,访问NULL指针的任何可能的错误都将保持未被检测到的状态,同时会导致危险的行为。
因此,我希望将NULL重新定义为另一个地址,例如,一个无效的地址。如果我不小心访问了这样的地址,我将得到一个硬件中断,我可以在其中处理错误。我恰好可以访问此编译器的stddef.h,因此实际上可以更改标准标头并重新定义NULL。
我的问题是:这会与C标准冲突吗?据我从标准7.17可以看出,该宏是实现定义的。标准中是否有其他内容说明NULL必须为0?
另一个问题是,无论数据类型如何,大量编译器通过将所有内容都设置为零来执行静态初始化。即使该标准规定编译器应将整数设置为零,并将指针设置为NULL。如果我为编译器重新定义NULL,那么我知道这种静态初始化将失败。即使我大胆地手动更改了编译器标头,我也可以认为这是不正确的编译器行为吗?因为我可以肯定地知道该特定的编译器在执行静态初始化时不会访问NULL宏。
C标准不需要将空指针指向机器的地址零。但是,将0
常量转换为指针值必须得到一个NULL
指针(第6.3.2.3/3节),并且将空指针评估为布尔值必须为false。这可以是一个有点尴尬,如果你真的不想要一个零个地址,而NULL
不是零个地址。
不过,通过对编译器和标准库进行(大量)修改,NULL
在仍然严格符合标准库的情况下,可以用备用位模式表示并非不可能。这是不足够简单地改变的定义NULL
然而本身,然后NULL
将评估为true。
具体来说,您需要:
-1
。0
以代替以检查魔术值(第6.5.9 / 6节)有一些事情你不具备处理。例如:
int x = 0;
void *p = (void*)x;
此后,p
不能保证是空指针。只需要处理常量分配(这是访问真实地址零的好方法)。同样地:
int x = 0;
assert(x == (void*)0); // CAN BE FALSE
也:
void *p = NULL;
int x = (int)p;
x
不保证是0
。
简而言之,C语言委员会显然考虑了这种情况,并为那些选择NULL的替代表示形式的人员进行了考虑。您现在要做的就是对编译器进行重大更改,并且嘿,您已经完成了:)
附带说明,在编译器适当之前,可以通过源代码转换阶段实现这些更改。也就是说,您将添加一个预处理器-> NULL转换->编译器->汇编器->链接器,而不是正常的预处理器->编译器->汇编器->链接器。然后,您可以进行如下转换:
p = 0;
if (p) { ... }
/* becomes */
p = (void*)-1;
if ((void*)(p) != (void*)(-1)) { ... }
这将需要完整的C解析器,类型解析器以及对typedef和变量声明的分析,以确定哪些标识符对应于指针。但是,这样做可以避免必须对编译器的代码生成部分进行适当的更改。clang可能对实现此功能有用-我了解它在设计时就考虑了这种转换。当然,您仍然可能需要对标准库进行更改。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句