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

Is it undefined behavior to take the address of an uninitialized pointer?

N1570 指出这是未定义的行为:

§J.2/1 The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.9, 6.8).

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

§6.7.9/10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:

— if it has pointer type, it is initialized to a null pointer;

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

#include <stdio.h>

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

我最关心的是 strtol 函数。先引用一下N1570中与endptr参数相关的部分:

§7.22.1.4/5 If the subject sequence has the expected form and the value of base is zero, the sequence of characters starting with the first digit is interpreted as an integer constant according to the rules of 6.4.4.1. [...] A pointer to the final string is stored in the object pointed to by endptr, provided that endptr is not a null pointer.

§7.22.1.4/7 If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a null pointer.

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

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

然而,this highly upvoted answer as well as this man page 都显示 endptr 被传递给 strtol 未初始化。是否存在使这不是未定义行为的异常?

指针的值和它的地址不一样。

void *foo;

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

至少这是我的直觉理解,我现在没有去挖掘标准,我只是觉得你看错了。

在谈论代码时,两者有时会混淆("what's the address of that pointer?" 可以表示"what's the value of that pointer, what address is it pointing to?")但它们确实截然不同。

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

strtol 上的标准引述是什么:

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

上面的引述是关于这样的电话:

strtol(str, 0, 10);

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

看这个例子

char * ptr; 

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

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

在声明中

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

strtolendptr 参数指向对象 ptr 并且取消引用它不会调用任何 UB。

在这个表达式中:

&ptr

&操作数的地址,i。即,生成 ptr 对象的地址,但从未评估 ptr 对象。

(C11, 6.3.2.1p2) "Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion."

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

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

特别是第 3 段(我强调):

Semantics

3 The unary & operator yields the address of its operand. If the operand has type ''type'', the result has type ''pointer to type''. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand.

None OP 中引用的段落适用,因为正如许多人指出的那样。东西的价值和它的地址是非常不同的。

我会争辩说,没有任何关于未初始化值取其地址的限制是允许的(因为没有禁止)。

注意:我们都知道这很好,但很少在这些标准中找到明确说明 "Yes you can do so & so."

的语句