首页 > 解决方案 > 为什么不将 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);
...

在这里,dconst char 变量只被mov编入堆栈,但它的名字(翻录位置)不在 in .section .rodata,这是为什么呢?当它具有 const 修饰符时。作为char*字符串,它自动放置在rodata上(char* 甚至不需要 const 修饰符)。我在某处读过 constness 是继承的(这意味着一旦使用 const 修饰符声明了一个变量,那么即使强制转换导致丢弃的 constness 也不会改变 constness - 即它将保持不变)。但是这里甚至没有考虑 const char 修饰符(直接通过堆栈操作,就像数组一样)。为什么?

标签: cx86charcompiler-construction

解决方案


该变量d不是静态的,而是函数局部变量。如果包含它的函数被多次调用(递归地,或在多个线程中同时调用),您将获得变量的多个实例(在函数的堆栈框架内),每个实例都有自己的单独地址,即使所有这些实例包含相同的数据。C 标准要求这些实例是不同的。如果您将变量定义为static,编译器可能会将其移动到该.rodata部分中,以便您仅获得一个实例。

但是,字符串文字(例如"foo")在出现在(递归)函数中时不需要具有单独的地址(除非它们用于初始化char数组),因此编译器通常将它们放在一个.rodata部分中。


推荐阅读