C语言中常数的存储地址
我正在学习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
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保留了下来。