以下语句是否将物理地址或虚拟地址分配给指针?

时间:2018-09-06 15:00:05

标签: c pointers null-pointer

来自https://stackoverflow.com/a/2761494/156458

  

C和C ++均未提供严格定义的功能,该功能允许   您可以将特定的物理地址分配给指针。所以你   关于“如何将0地址分配给指针”的问题   没有答案。您根本无法将特定地址分配给指针   在C / C ++中。但是,在实现定义的功能领域,   明确的整数到指针的转换旨在   影响。因此,您可以按照以下步骤进行操作

uintptr_t address = 0;
void *p = (void *) address;
     

请注意,这与这样做不同

void *p = 0;
     

后者总是产生空指针值,而前者在   一般情况没有。前者通常会产生一个指向   物理地址0,它可能是也可能不是空指针值   在给定的平台上。

令我惊讶的是,发现void *p = 0没有分配物理地址或虚拟地址0,而是将void的空指针分配给了指针。

引言还说,“显式整数到指针的转换”可以为指针分配地址。

问题:

    void *p = 0中的
  1. ,是否存在从0void*的隐式转换?

    隐式转换是否与显式转换(void *)0相同,即void *p = 0void *p = (void*) 0相同吗?

    void *p = (void*) 0是否产生指向物理或虚拟地址0的指针 还是void的空指针?

  2. 如果我使用非零数字,例如void *p = 123,是否隐含 从123void *的转换?

    隐式转换与显式转换(void *) 123相同吗?

    void *p = 123void *p = (void *)123设为p 指向物理地址还是虚拟地址123的指针?

    如果void *p = (void *)123无法生成指向物理地址或虚拟地址123的指针,int addr = 123; void *p = (void *)addr;可以吗?我通过在引号的第一个示例中将unitptr_t替换为int来创建它。

谢谢。

2 个答案:

答案 0 :(得分:3)

如果你说

char *p = 0x12345;

您可能会分配p指向地址0x12345。无论是虚拟地址还是物理地址,我们都不能说。这取决于您的计算机及其配置。 (但是,如果您的计算机使用虚拟内存,并且正在编写普通的用户程序,那么它肯定是虚拟地址。)

在上面我说“大概”,部分原因是严格来讲,为指针分配整数并不明确。为了安全起见,您应该写

char *p = (char *)0x12345;

这将再次分配p指向地址0x12345

但是接下来我们来谈谈特殊情况。如果你写

char *p = 0;

char *p = (char *)0;

问题是,您是否已分配p指向地址0?答案可能是在任何传统机器上,但这不能保证,因为对于空指针有一种特殊情况。

不是p = 0 不会分配p指向地址0,而是可能。在空指针的内部表示形式不是全零的机器上,赋值p = 0会将p设置为该空指针值,因此p不是指向地址0。

答案 1 :(得分:2)

TL; DR:您要问的大部分是特定于实现的行为和语言扩展领域。如果您确实需要这种行为,请查阅编译器文档。

  
      
  1. void *p = 0中,是否存在从0void*的隐式转换?
  2.   

初始化不符合要求,但是许多编译器都接受它作为扩展。确实根据需要定义结果的人,但实际上,它们确实提供了对void *的隐式转换。

因为文字0是一个“空指针常量”,因为初始化程序执行与简单赋值相同的转换,并且因为简单赋值为将空指针常量赋给指针提供了特殊情况,所以,{ {1}}被隐式转换为类型0。此外,由于void *是空指针常量,因此这种转换会导致类型为0的空指针。

  

隐式转换是否与显式转换void *相同,即(void *)0void *p = 0相同?

有充分的理由期望接受前一种形式的编译器将与后者完全相同,但是同样,前者是不合格的,并且将其接受为扩展名的实现定义了它们。自己的语义。

是的。 C无处可区分通过强制类型转换显式指定的转换效果和相同类型之间的自动转换。

  

void *p = (void*) 0是否产生指向物理地址或虚拟地址0的指针或void *p = (void*) 0的空指针?

它将初始化void以包含一个空指针(类型为p)。根据C,空指针不会指向任何对象,并且C除了对象或函数的地址之外没有任何地址意义,因此至少在这种意义上,将此类指针解释为指向任何特定地址是不正确的。取消引用此类指针的效果不是由C定义的,但是可能由某些实现定义-可能试图访问地址为0的对象。

  
      
  1. 如果我使用非零数字,例如void *,是否存在从void *p = 123123的隐式转换?
  2.   

该初始化不符合要求,但是某些编译器提供了隐式转换作为扩展。

  

隐式转换与显式转换void *相同吗?

有很好的理由期望编译器完全实现这种隐式转换,但又要实现“扩展”。

  

(void *) 123void *p = 123会成为void *p = (void *)123指向物理地址或虚拟地址p的指针吗?

这是实现定义的。同样,C除了对象或函数的地址之外,没有其他意义的地址,特别是它本身拒绝指定将整数转换为指针类型的结果,除了首先通过将指针转换为整数而获得的整数外,对于值为0的整数常量表达式。

但是,在某些实现中,将整数(值为0的整数常量除外)转换为指针具有将整数解释为地址,并转换为指向该地址的指针的效果,就好像存在一个具有该地址的对象。在托管 C实现中,这通常是虚拟地址。在独立实现中,它通常是物理地址。一些实现方式也可以将此行为扩展为值为0的整数常量,该常数可能会或可能不会固有地不一致。

  

如果123无法生成指向物理地址或虚拟地址void *p = (void *)123的指针,123可以吗?我通过在引号的第一个示例中将int addr = 123; void *p = (void *)addr;替换为int来创建它。

完全有理由期望显式转换值为{123的unitptr_t变量的结果与显式转换为值123的整数常量的结果完全相同,但是从技术上讲,它是实现定义的可能会为合规的编译器留下区别的空间。