获取未初始化指针的地址是未定义的行为吗?

时间:2015-02-18 15:17:14

标签: c pointers language-lawyer undefined-behavior

N1570声明这是未定义的行为:

  

§J.2/ 1使用具有自动存储持续时间的对象的值   虽然它是不确定的(6.2.4,6.7.9,6.8)。

在这种情况下,我们的指针有一个不确定的值:

  

§6.7.9/ 10如果具有自动存储持续时间的对象不是   显式初始化,其值是不确定的。如果一个对象那个   静态或线程存储持续时间未明确初始化,   然后:

     

- 如果它有指针类型,则将其初始化为空指针;

然后我推测以下测试程序表现出未定义的行为:

#include <stdio.h>

int main(void) {
    char * ptr;
    printf("%p", (void*)&ptr);
}

我的动机是strtol功能。首先,让我引用与endptr参数相关的N1570部分:

  

§7.22.1.4/ 5如果主题序列具有预期的形式和   base的值为零,以#开头的字符序列   第一个数字被解释为一个整数常数   6.4.4.1的规则。 [...]指向最终字符串的指针存储在   endptr指向的对象,前提是endptr不为空   指针。

     

§7.22.1.4/ 7如果主题序列为空或没有   预期形式,不进行转换; nptr的值是   存储在endptr指向的对象中,前提是endptr   不是空指针。

这意味着endptr需要指向一个对象,并且endptr在某个时候被解除引用。例如,this implementation does so

if (endptr != 0)
    *endptr = (char *)(any ? s - 1 : nptr);

然而,this highly upvoted answer以及this man page都显示endptr传递给strtol未初始化。是否有一个异常会导致这种行为不明确?

5 个答案:

答案 0 :(得分:9)

指针的值及其地址不相同。

void *foo;

该指针具有未定义的值,但foo的地址,即&foo的值必须是明确的(否则我们无法访问它)。

至少这是我的直觉理解,我现在没有挖掘标准,我只是认为你误读了它。

在谈论代码时,两者有时会混淆(“指针的地址是什么?”可以表示“指针的值是什么,它指向的是什么地址?”)但是他们真的很不同。

答案 1 :(得分:4)

在这个表达式中:

&ptr

&操作数的地址,i。例如,ptr对象的地址已生成,但永远不会评估ptr对象。

(C11,6.3.2.1p2)“除非它是sizeof运算符,一元&amp;运算符,++运算符, - 运算符或。运算符的左操作数或赋值的操作数。运算符,没有数组类型的左值被转换为存储在指定对象中的值(并且不再是左值);这称为左值转换。“

答案 2 :(得分:2)

没有。它不是未定义的行为。只有ptr未初始化且具有不确定的值,但&ptr具有适当的值。

strtol上的标准引言说:

...如果主题序列为空或者没有预期的形式,则不进行转换; nptr的值存储在endptr指向的对象中,前提是endptr不是空指针。

以上引用是关于这样一个电话的讨论:

strtol(str, 0, 10);

手册页中的调用和链接的答案完全没问题。

答案 3 :(得分:2)

参见此示例

char * ptr; 

由于ptr未指向任何对象,因此取消引用它会调用未定义的行为。但是当你将其地址传递给strtol时,有语法

long int strtol(const char *nptr, char **endptr, int base);  

在声明中

long parsed = strtol("11110111", &ptr, 2);   

endptr的{​​{1}}参数指向对象strtol,并且取消它后将不会调用任何UB。

答案 4 :(得分:0)

我只能访问N1256,但如果有任何重大变化,我会感到惊讶。

最相关的部分是“6.5.3.2地址和间接操作符”

特别是第3段(我的重点):

  

语义

     

3 一元&amp;运算符产生其操作数的地址。如果   操作数具有类型''type'',结果具有类型''指向类型''的指针。如果   操作数是一元*运算符的结果,也不是该运算符的结果   也不是&amp;运算符被评估,结果就像两者都是   省略,除了对运算符的约束仍然适用和   结果不是左值。同样,如果操作数是结果   一个[]运算符,不是&amp;算子也不是一元的*   评估[]所暗示的结果,就好像&amp;操作者   被删除,[]运算符被更改为+运算符。   否则,结果是指向对象或函数的指针   由其操作数指定。

OP中引用的段落均未适用,因为许多人已指出。某事物的价值及其地址是非常不同的。

我认为对&amp; amp;没有任何限制关于未经初始化的价值,允许(通过没有禁令)。

注意:我们都知道这很好,但很难在这些标准中找到明确说“是的,你可以这样做等等。”