C语言中常数的存储地址

C语言中常数的存储地址,c,pointers,memory,constants,memory-address,C,Pointers,Memory,Constants,Memory Address,我正在学习C语言中的指针,我有几个问题。 下面是一段代码,仅作为示例 int var = 300; char s[] = "Clang"; char *p = "Wonder"; 我知道所有变量的地址都在内存中。 像var和s和p这样的变量在内存中有自己的地址 但我想知道常量是否也有内存地址 300,“叮当声”,“奇迹”本身是否有内存地址?变量和常量的内存使用是编译器实现的问题。实际上,常数定义如下: const *foo = "bar&qu

我正在学习C语言中的指针,我有几个问题。 下面是一段代码,仅作为示例

int var = 300;
char s[] = "Clang";
char *p  = "Wonder";
我知道所有变量的地址都在内存中。 像
var
s
p
这样的变量在内存中有自己的地址

但我想知道常量是否也有内存地址


300
“叮当声”
“奇迹”
本身是否有内存地址?

变量和常量的内存使用是编译器实现的问题。实际上,常数定义如下:

const *foo = "bar";
const int answer = 42;
const int foo = 3;
int x = foo * 4;
通常会占用内存并有地址。也就是说,在运行时程序地址空间中的某个位置,您会发现表示文本“bar”的字节序列和表示数字42的字节序列

然而,由于现代编译器进行了积极的优化,一些常量可能根本不存在运行时,这是有道理的。例如,在这样的代码段中:

const *foo = "bar";
const int answer = 42;
const int foo = 3;
int x = foo * 4;
可以想象,如果
foo
从未在其他任何地方使用,编译器可能(实际上)将其转换为:

int x = 12;
而且
foo
在运行时甚至不存在

顺便说一句,许多开发人员认为C预处理器宏是“常量”:


这些通常不会在运行时占用内存,因为它们在编译时被替换到代码中。

只有对象和函数在C中有地址。命名变量是对象。本身使用的字符串文字
“Wonder”
是一个对象,一个由7个字符(即
char[7]
)组成的数组,即6个可见字符和终止的空字符,因此可能有一个地址。literal
“Clang”
在这里是一种边界情况,严格来说它没有地址,因为它不是一个对象,只是一种特殊的初始值设定语法

C模型与Python编程语言完全不同,后者

a = 300
a
是一个没有地址的名称,而
300
是一个有地址的对象


这可能是因为C表示对象或函数有地址,但许多编译器优化代码,创建一个不遵循严格C抽象机器的可执行文件;因此,只有当您观察对象时,对象才可能有地址。

大多数实现将对象放在通常称为.text(code),.data-初始化数据、.bss-归零数据、.rodata-只读数据的“部分”中。

300
不是对象:它没有地址
“Clang”
nd
“Wonder”
这两个对象本身都是对象(类型数组分别为6和7个字符),并且都有自己的地址。您可以将
“Wonder”
的地址复制到代码中的
p
中。C标准描述了用于指定程序行为的计算模型。在该模型中,常量
300
不是一个对象,也没有地址,而字符串导致创建静态数组,这些数组是对象,并且确实有地址。然而,C标准并不要求实现完全遵循模型。只要程序的可观察行为(如其输出)相同,它们就可以优化程序并生成不同的代码……在您显示的代码中,如果编译器可以在没有地址的情况下初始化
s
(可能通过在指令中使用立即操作数),则“叮当声”可能不存在或者至少在某种程度上可以从程序中删除
s
“Wonder”
不太可能被删除,但它取决于
p
的使用方式。
s
p
之间的另一个区别是,在所有情况下(除了少数例外)
“Wonder”
都将存储在
.rodata
部分,并且无法修改。因此,
“Wonder”
中的字符无法修改。使用
s
“Clang”
仅用于初始化常规数组,并且可以修改
s
的内容。这并不能完全解决值300是否有地址的问题。我认为现在有了。但这类问题可能非常宝贵,最终得到的答案只有编译器设计师才能理解;)Re“严格地说它没有地址”:严格地说它确实有地址,在优化之前的C模型中。C标准明确指出,源文本中的字符串文字用于定义具有指定内容的静态数组,即使它用于初始化另一个数组。
“Wonder”
是一个由7个字符组成的数组,只是更习惯地说:
“Wonder”
的类型为
/*只读*/char[7]
@pmg oops:))最初我在回答中混淆了叮当声和惊奇,数字6保留了下来。