C访问空指针地址的标准兼容方式?
在C语言中,延迟空指针是未定义的行为,但是空指针值有一个位表示,在某些体系结构中,它指向一个有效地址(例如地址0)。C访问空指针地址的标准兼容方式?,c,language-lawyer,undefined-behavior,null-pointer,C,Language Lawyer,Undefined Behavior,Null Pointer,在C语言中,延迟空指针是未定义的行为,但是空指针值有一个位表示,在某些体系结构中,它指向一个有效地址(例如地址0)。 为了清楚起见,让我们把这个地址称为空指针地址 假设我想在一个不受限制地访问内存的环境中用C编写一个软件。进一步假设我想在空指针地址写入一些数据:如何以符合标准的方式实现这一点? 示例案例(IA32e): 由于UB(0是空指针的位表示) 由于C接近低级编程,我相信一定有办法访问空指针地址并避免UB 我想说清楚 我想问的是标准对此有何规定,而不是如何以实现定义的方式实现这一点。 我
为了清楚起见,让我们把这个地址称为空指针地址 假设我想在一个不受限制地访问内存的环境中用C编写一个软件。进一步假设我想在空指针地址写入一些数据:如何以符合标准的方式实现这一点? 示例案例(IA32e): 由于UB(0是空指针的位表示) 由于C接近低级编程,我相信一定有办法访问空指针地址并避免UB
我想说清楚
我想问的是标准对此有何规定,而不是如何以实现定义的方式实现这一点。
我知道后者的答案。我阅读了C99标准的(部分)以澄清我的想法。我找到了我自己的问题感兴趣的部分,我写这篇文章作为参考 免责声明
我是一个绝对的初学者,我写的90%或更多的东西都是错的,没有意义,或者可能会弄坏你的烤面包机。我还试图从标准中找出理由,通常会产生灾难性和幼稚的结果(如评论中所述)。
不要阅读。
请咨询@Olaf,获取正式和专业的答案 对于以下内容,术语体系结构地址设计了处理器所看到的内存地址(逻辑、虚拟、线性、物理或总线地址)。换句话说,您将在汇编中使用的地址
在第6.3.2.3节中。上面写着 值为0的整型常量表达式或转换为类型
void*
的此类表达式称为空指针常量。
如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证比较不相等
指向任何对象或函数的指针
关于整数到指针的转换
整数可以转换为任何指针类型。除前面指定的情况外[即,对于空指针常量的情况],
结果是定义了实现,可能没有正确对齐,可能没有指向
引用类型的实体,可能是陷阱表示†
这意味着编译器要兼容,只需实现从整数到
注意int2ptr(0)不是强制要求为0的。它可以是任何位表示
注意这意味着int2ptr不需要是标识函数,也不需要是返回有效指针的函数李> 根据下面的代码
char* p = (char*)241;
本标准绝对不保证表达式*p=56代码>将写入架构地址241。
因此它无法直接访问任何其他体系结构地址(包括int2ptr(0),该地址由空指针设计,如果有效)。
简单地说,该标准不涉及体系结构地址,而是涉及指针、它们的比较、转换及其操作
当我们编写类似于char*p=(char*)K
的代码时,我们并不是告诉编译器让p
指向体系结构地址K,而是告诉它从整数K中取出一个指针,或者换句话说,让p
指向(C抽象)地址K
空指针和(体系结构)地址0x0不相同(cit),因此对于由整数K和(体系结构)地址K构成的任何其他指针也是如此
出于某些原因,童年时代的传统,我认为C中的整数文字可以用来表示体系结构地址,而不是我错了,而这只在我使用的编译器中(某种程度上)是正确的
我自己问题的答案很简单:没有标准方法,因为C标准文档中没有(体系结构)地址。这适用于每个(体系结构)地址,而不仅仅是int2ptr(0)地址1
关于返回*(volatile char*)0的注释代码>
标准上说
如果
无效值[空指针值是无效值]已分配给指针,一元*运算符的行为未定义
那
因此,任何表示
对于此类[挥发性]对象,应严格按照抽象机器的规则进行评估
抽象机器说,*
对于空指针值是未定义的,因此代码不应该与此代码不同
返回*(char*)0代码>
这也是未定义的。
事实上,它们没有什么不同,至少在GCC 4.9中是这样,它们都是按照我问题中所述的指令编译的
对于GCC,实现定义的访问0体系结构地址的方法是使用-fno隔离错误路径解除引用标志,该标志生成“预期”的程序集代码
†用于将指针转换为整数或将整数转换为指针的映射函数旨在
与执行环境的寻址结构保持一致
‡不幸的是,它说,&
生成其操作数的地址,我认为这有点不恰当,我想说它生成指向其操作数的指针。考虑一个变量<代码> a <代码>,它位于16位地址空间中的地址0xf1,并考虑一个编译器,它实现了tn2ptR(n)=0x8000Ωn。代码>&a
woul
movzx eax, BYTE PTR [0]
ud2
char* p = (char*)241;
asm volatile("movzx 0, %%eax;") // *(int*)0;
*((uint32_t volatile*)0) = 0x12345678;
*((uint32_t volatile*)x) = 0x12345678;
_memory = 0;
extern char _memory[];