一、内存分布图
在操作系统中,内存被组织和管理以支持进程的运行。以下是一些常见的内存分布概念:
【内核空间】:操作系统内核使用的内存区域,用于存储内核代码、数据结构和进程控制块(PCB)。
【用户空间】:存储用户的代码。
未初始化变量区(.bss):存放未初始化的全局变量和静态变量。
已初始化变量区(.data):存放已初始化的全局变量和静态变量。
常量区(.rodata):存储程序中定义的所有字符串常量和其他被const修饰的全局变量。
栈区(.stack):用于函数调用时存储局部变量、参数和返回地址,空间通常向下增长(由高地址向低地址)。
堆区(.heap):用于动态内存分配,如 C 语言中的malloc或 C++中的new,空间通常向上增长(由低地址向高地址)。
数据区:存储全局变量、被const修饰的全局变量和被static修饰的静态变量。
文本区(.text):存储程序代码,通常是只读的,也就是只有访问权而没有写入权。
注意事项:
在 C 语言言中常量有很多种,比如常见的:
字符常量:'a','A','*'。
字符串常量:"helloworld","ilovechina","12345"。
整常量:25,10,012,0x0a,0b00001010。
浮点常量:3.14,123.456,3.0E-23。
但并不是所有的常量都会被编译器放在常量区的,例如:
#include <stdio.h>
int main(void)
{
int i = 10;
return 0;
}
代码中定义了一个整型局部变量i,并被初始化为了 10,其中i是变量,10是常量,但编译器并不将10放入常量区,而是在汇编指令中直接通过立即数赋值。
这是因为编译器认为普通的整型、浮点型或字符型常量所占空间很小,使用起来很简单,认为将它们直接嵌入到代码中,而不是单独存储在常量区,这样会更加高效。如此节省了运行、访问的时间和存储空间。
二、那什么样的数据才将放入常量区(.rodata
)呢?
1、字符串常量
#include <stdio.h>
int main(void)
{
char *p = "hello world";
return 0;
}
对于上方代码片段中的指针 char *p = "hello world";
,指针 p 存储在栈上,
"hello world"字符串被放置在程序的常量区(.rodata
) 中,指针 p 指向字符串常量 "hello world" 在常量区(.rodata
)中的地址。
这是因为字符串字面量在程序的整个生命周期内不会改变,因此放在常量区(.rodata
)可以节省内存并提高效率。
但是,当一个字符常量串被用来为数组初始化的时候,那么该字符串常量将不被放入常量区,而是放入对应的数组中,也就是数据区(.data)中。
例如:
#include <stdio.h>
int main(void)
{
char str[20] = "hello world";
return 0;
}
对于数组char str[20] = "hello world";
,字符串常量 "hello world" 本身是存储在 .text区,但在初始化的过程中,该字符串会被复制到 str 数组中。这意味着字符串的实际内容会存储在 str 数组所在的内存区域,即在程序的数据段中(通常被称为.data
区)。
两者不同的地方在于指针 p 本身存储在栈上,指向只读数据段中的字符串常量,而数组 str 存储在数据段中,并包含字符串常量"hello world"的副本。
2、 被const修饰的全局变量
#include <stdio.h>
const int value_0 = 10;
int value_1 = 20;
int main(void)
{
const int value_2 = 30;
return 0;
}
value_0全局变量被const修饰,所以被存储在常量区(.rodata
)中;而value_1变量虽然也是全局变量,但并没有被const修饰,所以存储在了(.data
)中。
但并不是所有被const修饰的变量都存储在常量区(.rodata
),例如value_2变量是局部变量,被const修饰后仅仅意味着在表达式上不能显式地更改变该变量的值,否则语法错误,但该变量仍存放在栈区。
标签:存储,const,常量,int,编程,嵌入式,内存,字符串,world From: https://www.cnblogs.com/o-O-oO/p/18653331原创 ZRQRS 知睿电子工程师