重新定义NULL [英] Redefining NULL

查看:184
本文介绍了重新定义NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写C code代表一个系统,其中0x0000地址是有效的,包括I / O端口。因此,访问一个空指针的任何可能的错误无法被检测到,并在同一时间造成危险的行为。

I'm writing C code for a system where address 0x0000 is valid and contains port I/O. Therefore, any possible bugs that access a NULL pointer will remain undetected and at the same time cause dangerous behaviour.

有关这个原因,我希望重新定义NULL是另一个地址,为例子,是无效的地址。如果我不小心访问这样的地址,我会得到一个硬件中断,我可以处理错误。我正好有机会获得STDDEF.H编译器的,所以其实我可以改变标准头并重新定义NULL。

For this reason I wish to redefine NULL to be another address, to for example an address that isn't valid. If I accidentally access such an address I will get a hardware interrupt where I can handle the error. I happen to have access to stddef.h for this compiler, so I can actually alter the standard header and redefine NULL.

我的问题是:与C标准这个矛盾呢?据我可以从标准的7.17来讲,宏观是实现定义的。有什么其他的标准,说明空的必须的是0?

My question is: will this conflict with the C standard? As far as I can tell from 7.17 in the standard, the macro is implementation-defined. Is there anything elsewhere in the standard stating that NULL must be 0?

的另一个问题是,大量的编译器通过一切设置为零,不管数据类型执行静态初始化。尽管标准说编译器应该设置整数零和指针为NULL。如果我将重新定义为NULL我的编译器,后来我才知道,这种静态初始化将失败。我认为这是不正确的编译器行为,即使我大胆地手动更改编译头?因为我知道肯定,这样做静态初始化时,这个特殊的编译器不访问NULL宏。

Another issue is that plenty of compilers perform static initialization by setting everything to zero, no matter the data type. Even though the standard says that the compiler should set integers to zero and pointers to NULL. If I would redefine NULL for my compiler, then I know that such static initialization will fail. Could I regard that as incorrect compiler behaviour even though I boldly altered compiler headers manually? Because I know for certain that this particular compiler does not access the NULL macro when doing static initialization.

推荐答案

C标准不要求空指针是在机器的地址为零。然而,在浇铸一 0 常量的指针值必须产生一个 NULL 指针(§6.3.2.3/ 3)和评估空指针作为一个布尔值一定是假的。这可以是一个有点尴尬,如果你真的不要的想要一个零地址,而 NULL 不是零地址。

The C standard does not require null pointers to be at the machine's address zero. HOWEVER, casting a 0 constant to a pointer value must result in a NULL pointer (§6.3.2.3/3), and evaluating the null pointer as a boolean must be false. This can be a bit awkward if you really do want a zero address, and NULL is not the zero address.

然而,随着(重型)修改编译器和标准库,这不是不可能有 NULL 重新使用备用位模式psented $ P $同时,仍保持严格一致性的标准库。它的的足以简单地改变定义 NULL 本身不过,由于随后 NULL 将评估为true。

Nevertheless, with (heavy) modifications to the compiler and standard library, it's not impossible to have NULL be represented with an alternate bit pattern while still remaining strictly conformant to the standard library. It is not sufficient to simply change the definition of NULL itself however, as then NULL would evaluate to true.

具体而言,您将需要:


  • 安排在分配的指针文字零(或强制转换为指针)转换成一些其他的魔法值,如 1

  • 安排指针和一个整型常量 0 来检查魔法值代替(§6.5.9/ 6)
  • 之间的平等测试
  • 安排在其中一个指针类型被评价为一个布尔检查平等的魔法值,而不是检查零所有上下文。在此之前,从平等的测试语义,但是编译器可以实现不同的看法内部。见§6.5.13/ 3,§6.5.14/ 3,§6.5.15/ 4,§6.5.3.3/ 5,§6.8.4.1/ 2,§6.8.5/ 4

  • 作为非洲足联指出,更新静态对象的初始化(§6.7.8/ 10)和部分复合初始化(§6.7.8/ 21)的语义以反映新的空指针重新presentation。

  • 创建访问真实地址零点的另一种方法。

  • Arrange for literal zeros in assignments to pointers (or casts to pointers) to be converted into some other magic value such as -1.
  • Arrange for equality tests between pointers and a constant integer 0 to check for the magic value instead (§6.5.9/6)
  • Arrange for all contexts in which a pointer type is evaluated as a boolean to check for equality to the magic value instead of checking for zero. This follows from the equality testing semantics, but the compiler may implement it differently internally. See §6.5.13/3, §6.5.14/3, §6.5.15/4, §6.5.3.3/5, §6.8.4.1/2, §6.8.5/4
  • As caf pointed out, update the semantics for initialization of static objects (§6.7.8/10) and partial compound initializers (§6.7.8/21) to reflect the new null pointer representation.
  • Create an alternate way to access true address zero.

有一些事情你做的的必须处理。例如:

There are some things you do not have to handle. For example:

int x = 0;
void *p = (void*)x;

在此之后, P 是不能保证是一个空指针。只有不断的任务需要进行处理(这是访问的真实地址为零的好方法)。同样的:

After this, p is NOT guaranteed to be a null pointer. Only constant assignments need be handled (this is a good approach for accessing true address zero). Likewise:

int x = 0;
assert(x == (void*)0); // CAN BE FALSE

还有:

void *p = NULL;
int x = (int)p;

X 不能保证是 0

总之,这很状况显然是由C语言委员会审议,并为那些谁都会选择一个备用重新presentation为NULL作出考虑。所有你现在要做的就是做出重大改变,你的编译器,哎你就大功告成了preSTO:)

In short, this very condition was apparently considered by the C language committee, and considerations made for those who would choose an alternate representation for NULL. All you have to do now is make major changes to your compiler, and hey presto you're done :)

作为一个侧面说明,有可能实现这些变化编译器之前源$ C ​​$ C转换阶段。也就是说,不是preprocessor的正常流动, - >编译器 - >汇编 - >连接器,你会增加preprocessor ​​ - > null转换 - >编译器 - >汇编 - >连接器。然后,你可以做这样的转换:

As a side note, it may be possible to implement these changes with a source code transformation stage before the compiler proper. That is, instead of the normal flow of preprocessor -> compiler -> assembler -> linker, you'd add a preprocessor -> NULL transformation -> compiler -> assembler -> linker. Then you could do transformations like:

p = 0;
if (p) { ... }
/* becomes */
p = (void*)-1;
if ((void*)(p) != (void*)(-1)) { ... }

这将需要一个完整的C解析器,以及一个类型解析器和分析typedef和变量声明,以确定哪些标识符对应的指针。然而,这样做,你可以避开不必更改编译器正确的code一代的部分。 可能实现这个有用的 - 我明白这是设计时考虑了这样的转变。你仍然有可能需要进行更改标准库以及课程。

This would require a full C parser, as well as a type parser and analysis of typedefs and variable declarations to determine which identifiers correspond to pointers. However, by doing this you could avoid having to make changes to the code generation portions of the compiler proper. clang may be useful for implementing this - I understand it was designed with transformations like this in mind. You would still likely need to make changes to the standard library as well of course.

这篇关于重新定义NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆