【问题标题】:Lifetime of literals in CC中文字的生命周期
【发布时间】:2018-05-23 14:05:01
【问题描述】:

这个网站上有很多关于字符串文字的静态生命周期的好答案。据我了解,它们被分配在只读内存中(其他人专门提到了“字符串文字池”)。因此,返回指向字符串文字的指针不会导致悬空指针。它们也是左值。

为什么对于整数常量字面量不成立?它也没有静态存储持续时间吗?如果我尝试分配一个整数常量,gcc 会抱怨它不是左值。

为什么要对字符串文字进行这种特殊处理? (以及 C99 中的复合文字)。我听说过左值的以下定义:“左值(定位器值)表示占据内存中某个可识别位置(即具有地址)的对象。”如果字符串文字(字符数组类型)必须在内存中可寻址,为什么同样不适用于整数?即使是整数也必须在程序的地址空间中分配。有性能原因吗?

【问题讨论】:

  • 字符串文字不是处理器原生的东西。它们必须存储在内存中(除非它们很短),而诸如整数常量之类的“文字”可以自然地作为操作数传递给相应的汇编指令和/或存储在寄存器中.当然还有一些历史原因......
  • 可能与字符串文字不是奇异值这一事实有关。 int 只是编译器可以直接传递给指令的值。另一方面,字符串是一个由其地址操作的数组,这意味着它需要存在于内存中的某个位置。指向字符串文字的指针可能与使用整数常量得到的字符串等价。
  • char *p = "Hello"; 允许有用,int *p = &3; 没那么有用
  • 请注意,您可以制作左值文字,例如int *p = &(int){3};
  • 相关但不重复:String literals: Where do they go?

标签: c


【解决方案1】:

整数常量文字不是左值(参见 C 标准 n1570 §6.3.2.1),并且(或者可能是因为)通常甚至不在可寻址内存中。但是,字符串文字是不应修改的左值 (§6.4.5)(否则为 undefined behavior)。

在许多情况下,足够小的整数文字被翻译成单个机器代码指令的子部分,并且没有任何位置。

对于一些愚蠢的例子,int zero(void) { return 0; } 被编译(在 Linux/x86-64/Debian 上使用 GCC 8.1)和 gcc -O2 -S -fverbose-asm

    .globl  zero
    .type   zero, @function
zero:
.LFB0:
    .cfi_startproc
# zero.c:1: int zero(void) {return 0;}
    xorl    %eax, %eax  #
    ret 
    .cfi_endproc

您在生成的机器代码中没有看到任何提及0

当然,关于整数字面量实现的细节显然是特定于实现的。它们取决于指令集架构、优化级别、编译器版本、月相、我的猫的心情(我不确定最后两项,我让你检查)。

【讨论】:

  • 是的,但是编译器在不改变程序操作的情况下进行特定优化这一事实并不意味着语言的语义。 IIRC,早期的 Fortran 是通过引用传递的,因此在内存中实现了常量,您可以在过程中分配一个新值,比如 2,这不是很有用。
  • 出于好奇,数组初始值设定项表达式(例如 {1, 2, 3})是否给予与字符串文字类似的处理?如果它正在初始化的变量是自动的,那么对象 {1, 2, 3} 是否可以在只读内存中以静态持续时间寻址?如果不是,编译器在内存分配方面区分“123”和{1,2,3}的理由是什么?
【解决方案2】:

为什么对于整数常量字面量不成立?可以 不是也有静态存储时长吗?

整数常量不是标准术语中的“文字”。 “常数”是一个单独的东西。不,常量没有静态存储持续时间,因为它们根本不是对象。它们是常数。 C 没有将它们定义为具有任何类型的存储。在实践中,它们通常直接表示在生成的可执行代码中,而不是在程序的数据中。

如果我尝试分配给 整数常量,gcc 抱怨它不是左值。

不是。换句话说,常数不对应于内存位置,它只是一个常数。

为什么要对字符串文字进行这种特殊处理? (和复合 C99 中的文字)。

对字符串和复合字面量的处理并没有什么特别之处,就是它本来的样子。您似乎因为错误地认为这些类型的对象文字与常量类似而感到困惑,但事实并非如此。字符串和复合字面量表示确实在内存中作为数据表示的对象。

我听说过左值的以下定义:“一个 lvalue(定位器值)表示一个对象占用了一些 内存中可识别的位置(即有地址)。”

是的。

如果是一个字符串 文字(字符数组类型)必须在内存中可寻址,为什么 这同样不适用于整数吗?

你又跑题了。整数可以而且经常确实在内存中有可寻址的位置。但是整数 constants 没有(或者至少,C 不要求它们具有)。它们在程序中的表示形式通常是可执行代码。

术语“文字”的部分意义在于,如此描述的实体代表了指定类型的实际对象

另一方面,“常量”表示指定类型的

即使是整数也必须是 分配在程序的地址空间中。

这里有一个微妙的区别,但很重要,对象和值之间。用存储位置标识对象;它们和/或包含值。因此,整数类型的对象确实具有存储空间,并且指定存储空间的表达式是左值。另一方面,虽然一个特定的整数值实际上可能是任意数量的对象的值,但该值本身并不与特定的存储位置有内在关联。

有演出吗 原因?

从根本上说,有语言设计的原因。其中一些确实提高了性能——即可以将值直接编码为可执行的机器代码,而不是机器代码必须从(其他)内存加载它们——但我不认为这些是主要因素。

【讨论】:

    【解决方案3】:

    C 字符串文字是左值的原因是因为它们在技术上是 char[] 类型的数组,并且数组必须始终在内存中可寻址。

    如果您要问为什么,我最好的猜测是因为将文字作为左值是没有意义的,但是由于无论如何都无法分配数组,因此不必费心显式在这种情况下(字符串文字)禁止它作为左值。对编译器的构造更了解的人可能会提供更完整的解释。

    【讨论】:

      猜你喜欢
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多