C++ 在指针变量中存储除零以外的整数常量

C++ 在指针变量中存储除零以外的整数常量,c++,c,C++,C,这个很好用 int main() { int *d=0; printf("%d\n",*d); return 0; } 如果我更改语句int*d=0至int*d=1 我看到了错误 >cc legal.c > ./a.out 0 很明显,它只允许零。我想知道当我们这样做时,内存中发生了什么,这使得它的语法有效 我问这个只是出于好奇 我很惊讶你在运行代码时没有遇到SEGFAULT。printf语句中的*d正在解引用指针。但是,为了回答你的问题,C++允许0作为任何对象的默认初始化

这个很好用

int main()
{

int *d=0;
printf("%d\n",*d);

return 0;
}
如果我更改语句
int*d=0
int*d=1
我看到了错误

>cc legal.c
> ./a.out
0
很明显,它只允许零。我想知道当我们这样做时,内存中发生了什么,这使得它的语法有效


我问这个只是出于好奇

我很惊讶你在运行代码时没有遇到SEGFAULT。printf语句中的
*d
正在解引用指针。但是,为了回答你的问题,C++允许0作为任何对象的默认初始化器,这就是为什么它可以用来初始化指针为null(0和null是相同的)。值为1时,您要求编译器将整数转换为指针,这需要显式转换。

您正在堆栈上创建一个名为
d
的指针变量,该变量称为“指向整数”。然后将指针变量指定给0,使其指向有效的内存地址0x0(与C中的
NULL

为了更清楚地说明这一点,
int*d=0
与以下内容相同:

cc: "legal.c", line 6: error 1522: Cannot initialize a pointer with an integer constant other than zero.
如果要指向整数
1
,则需要:

   int *d;
   d = 0;       // set it to address 0

使用
0
初始化指针时,该
0
将隐式转换为空指针。空指针的外观取决于您的平台,编译器将使用正确的二进制值


当您尝试使用
1
(或任何其他非零整数)初始化指针时,编译器不知道如何将此值转换为有效指针,并发出警告。

如果*d=0,则整数指针d将被初始化为有效的0。基本上,您是在声明一个整数指针,因此初始化指针是有意义的

但是,您不想初始化指针,而是要初始化指针指向的内存,这是不正确的

当执行*d=1时,指针值变为1,当执行printf语句时,它将尝试访问地址1处的值,这是不允许的

希望这有帮助。

在您的“工作”示例中,您正在取消对空指针的引用,而该语言正在将找到的任何位作为printf的参数。它的工作完全依赖于编译器和机器的实现特性,可能会在另一个实现中出错


代码正常运行似乎表明编译器在幕后做了一些奇怪的事情,试图“保护”编码器免受非常常见的错误;那是个坏主意。我很想看看你的编译器在ISO-C99中使用cc-s生成了什么程序集,有两种类型的空指针常量:值的整数常量表达式
0
-eg
0
1-1
(int)0.0
-以及转换为
void*
-eg
(void*)0
,它通常用于定义
NULL

将空指针常量转换为任意指针类型将生成该类型的空指针。这种转换是隐式的,但实际上可能涉及地址转换,因为标准不要求空指针具有位表示0

此转换也为函数指针类型定义,即使将对象指针转换为函数指针通常是非法的:

   int x = 1;
   int *d = &x; // "set it to 'address of x'"

这也意味着您可以使用
0
来初始化任何标量类型,而无需强制转换,这是唯一正确的值:将
0
转换为指针类型将始终生成空指针,而转换任何其他整数值都是可能的,但需要显式强制转换,有一个实现定义的结果,可能由于对齐或地址空间限制而失败。

是的,我同意,但我的问题是*d=0时会发生什么。请更新它。希望它现在更有意义。@benjamin button:在这篇评论中,您询问了
*d=0
的情况,但您问题中的代码不符合
*d=0
。第一行中的
*
是变量类型的一部分,0被分配给
d
,而不是
*d
。不是*d=0*D未定义的行为?它是未定义的,所以我们不需要得到Sebug——在一些系统中,从地址0读取实际上是非陷阱的。您可以通过0来初始化任何C++对象吗?当然,不是自定义构造函数类。@ AshleysBrain,任何默认的可构造的自定义类,它没有提供一个构造函数,它需要一个int,一个指针,或者一些使它变得模棱两可的东西,在初始化列表中可以给出0,C++将推导默认的构造。@汤姆,它是未定义的行为,但任何合理的操作系统都会使内存区域受到保护,并导致程序突然终止。在Linux和Mac OS X上,可能会出现SEGFAULT或KERN_PROTECTION_FAILURE(EXC_BAD_ACCESS)故障。实际上,编译器将知道如何将非零整数转换为指针类型(这就是为什么C99添加了
intptr_t
/
uintptr_t
,即大到足以容纳任何
void*
)的整数类型,但转换需要显式铸造;此外,任意转换(即,所讨论的整数不是通过强制转换指针值获得的转换)可能会产生无效指针。在C99中,空指针常量是任何计算结果为0的整数常量表达式(ICE可能的任何类型)。因此,与您给出的一样,以下是空指针常量:
(0+0)
1-1
0L
0LL
(int)(0.0f)
void (*foo)(void) = (void *)0;           // valid
void *bar = 0;                           // valid
void (*baz)(void) = (void (*)(void))bar; // invalid even with explicit cast