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);
}
Run Code Online (Sandbox Code Playgroud)
我的动机是关注strtol功能.首先,让我引用与endptr参数相关的N1570部分:
§7.22.1.4/ 5如果主题序列具有预期形式且base的值为零,则根据6.4.4.1的规则将以第一个数字开头的字符序列解释为整数常量.[...]指向最终字符串的指针存储在指向的对象中
endptr,前提endptr是该指针不是空指针.§7.22.1.4/ 7如果主题序列为空或没有预期的形式,则不进行转换; 如果不是空指针,则值
nptr存储在指向的对象中.endptrendptr
这意味着endptr需要指向一个对象,并且endptr在某些时候也需要解除引用.例如,此实现是这样做的:
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
Run Code Online (Sandbox Code Playgroud)
然而,这个高度赞成的答案以及这个手册页都显示endptr被传递给strtol未初始化的.是否有一个例外,这使得这不是未定义的行为?
正如我从这个答案中了解到的,在 C 中使用未初始化变量的地址并不是未定义的行为。例如,我可以写:
#include <stdio.h>
int main(void) {
char letter;
printf("%p\n", &letter); //prints '0061ff1f'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我编写以下代码:
#include <stdio.h>
int main(void) {
char *letter1;
printf("%p\n", letter1); //gcc issues warning
return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc 给了我以下错误:
C:\...>gcc -Wall -Wextra -pedantic -std=c11 test.c -o main
test.c: In function 'main':
test.c:12:2: warning: 'letter1' is used uninitialized in this function [-Wuninitialized]
printf("%p\n", letter1);
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,未初始化的指针可能指向任何内存地址,这就是为什么使用它通常是一个坏主意。但是为什么同样的事情对未初始化的变量起作用,即为什么未初始化的变量不指向任何内存地址,而是指向我们可以安全使用的位置?为什么语言在这方面对待指针变量和普通变量的方式如此不同?