c - 为什么不将 const char 放入rodata 段?
问题描述
有这个:
#include <stdio.h>
#include <stdlib.h>
void f(const char *str){
char *p = (char*)str;
*p=97;
}
int main(){
char c;
f(&c);
char *p = malloc(10);
if (p) { f(p); printf("p:%s\n",p); free(p); }
const char d = 0; //only this part in interest
f(&d); // here the function modifies the the char, but since it is NOT in rodata, no problem
printf("d:%c\n",d);
printf("c:%c\n",c);
}
会产生气体:
...
.L3:
# a.c:16: const char d = 0;
movb $0, -10(%rbp) #, d
# a.c:17: f(&d);
leaq -10(%rbp), %rax #, tmp98
movq %rax, %rdi # tmp98,
call f #
# a.c:18: printf("d:%c\n",d);
movzbl -10(%rbp), %eax # d, d.0_1
movsbl %al, %eax # d.0_1, _2
movl %eax, %esi # _2,
leaq .LC1(%rip), %rdi #,
movl $0, %eax #,
call printf@PLT #
# a.c:20: printf("c:%c\n",c);
...
在这里,d
const char 变量只被mov
编入堆栈,但它的名字(翻录位置)不在 in .section .rodata
,这是为什么呢?当它具有 const 修饰符时。作为char*
字符串,它会自动放置在rodata上(char* 甚至不需要 const 修饰符)。我在某处读过 constness 是继承的(这意味着一旦使用 const 修饰符声明了一个变量,那么即使强制转换导致丢弃的 constness 也不会改变 constness - 即它将保持不变)。但是这里甚至没有考虑 const char 修饰符(直接通过堆栈操作,就像数组一样)。为什么?
解决方案
该变量d
不是静态的,而是函数局部变量。如果包含它的函数被多次调用(递归地,或在多个线程中同时调用),您将获得变量的多个实例(在函数的堆栈框架内),每个实例都有自己的单独地址,即使所有这些实例包含相同的数据。C 标准要求这些实例是不同的。如果您将变量定义为static
,编译器可能会将其移动到该.rodata
部分中,以便您仅获得一个实例。
但是,字符串文字(例如"foo"
)在出现在(递归)函数中时不需要具有单独的地址(除非它们用于初始化char
数组),因此编译器通常将它们放在一个.rodata
部分中。
推荐阅读
- ruby-on-rails - 更改嵌套内容的顺序
- amazon-web-services - AWS 参数存储:AWSSimpleSystemsManagementException:超出速率
- json - 即使我的令牌是正确的,我收到的输出消息是“缺少身份验证令牌”
- c# - WinCe 6 上的 Windows 窗体应用程序
- html - 如何使这部分全屏高度?无论我们做什么,它都会在底部留下空白
- sqlite - SQLite 错误外键不匹配 - 股票引用变体
- c - 如何创建输入的每个单词以开始新行
- ruby-on-rails - 如何通过指定控制器和动作来生成路径?
- javascript - 如何使用javascript隐藏过去的时间?
- apache - AH01114: HTTP: 无法连接到后端: localhost (apache 作为 docker 容器)