Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C访问空指针地址的标准兼容方式?_C_Language Lawyer_Undefined Behavior_Null Pointer - Fatal编程技术网

C访问空指针地址的标准兼容方式?

C访问空指针地址的标准兼容方式?,c,language-lawyer,undefined-behavior,null-pointer,C,Language Lawyer,Undefined Behavior,Null Pointer,在C语言中,延迟空指针是未定义的行为,但是空指针值有一个位表示,在某些体系结构中,它指向一个有效地址(例如地址0)。 为了清楚起见,让我们把这个地址称为空指针地址 假设我想在一个不受限制地访问内存的环境中用C编写一个软件。进一步假设我想在空指针地址写入一些数据:如何以符合标准的方式实现这一点? 示例案例(IA32e): 由于UB(0是空指针的位表示) 由于C接近低级编程,我相信一定有办法访问空指针地址并避免UB 我想说清楚 我想问的是标准对此有何规定,而不是如何以实现定义的方式实现这一点。 我

在C语言中,延迟空指针是未定义的行为,但是空指针值有一个位表示,在某些体系结构中,它指向一个有效地址(例如地址0)。
为了清楚起见,让我们把这个地址称为空指针地址

假设我想在一个不受限制地访问内存的环境中用C编写一个软件。进一步假设我想在空指针地址写入一些数据:如何以符合标准的方式实现这一点?

示例案例(IA32e):

由于UB(0是空指针的位表示)

由于C接近低级编程,我相信一定有办法访问空指针地址并避免UB


我想说清楚

我想问的是标准对此有何规定,而不是如何以实现定义的方式实现这一点。
我知道后者的答案。

我阅读了C99标准的(部分)以澄清我的想法。我找到了我自己的问题感兴趣的部分,我写这篇文章作为参考

免责声明
我是一个绝对的初学者,我写的90%或更多的东西都是错的,没有意义,或者可能会弄坏你的烤面包机。我还试图从标准中找出理由,通常会产生灾难性和幼稚的结果(如评论中所述)。
不要阅读。
请咨询@Olaf,获取正式和专业的答案

对于以下内容,术语体系结构地址设计了处理器所看到的内存地址(逻辑、虚拟、线性、物理或总线地址)。换句话说,您将在汇编中使用的地址


在第6.3.2.3节中。上面写着

值为0的整型常量表达式或转换为类型
void*
的此类表达式称为空指针常量。 如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证比较不相等 指向任何对象或函数的指针

关于整数到指针的转换

整数可以转换为任何指针类型。除前面指定的情况外[即,对于空指针常量的情况], 结果是定义了实现,可能没有正确对齐,可能没有指向 引用类型的实体,可能是陷阱表示†

这意味着编译器要兼容,只需实现从整数到

  • 根据定义,int2ptr(0)是空指针
    注意int2ptr(0)不是强制要求为0的。它可以是任何位表示
  • *int2ptr(n!=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[];