【问题标题】:Why does a function returning const char * with string literals work? [duplicate]为什么返回带有字符串文字的 const char * 的函数有效? [复制]
【发布时间】:2019-10-04 08:33:27
【问题描述】:

我在 libcurl 中找到了 code,它看起来像:

const char *
curl_easy_strerror(CURLcode error)
{
  switch(error) {
  case CURLE_OK:
    return "No error";

  case CURLE_UNSUPPORTED_PROTOCOL:
    return "Unsupported protocol";
.....
}

据我所知,如果你想返回一个指针,你需要确保指针指向的内存不会被改变或释放。为什么这个 libcurl 代码有效?

【问题讨论】:

  • 如果你想返回一个指针,你需要确保在你返回它之后它会指向一个有效的东西。 malloc 是一种方法,但不是唯一的方法。
  • 指向静态的、全局的或在本例中为文字常量的指针也是有效的。
  • 您选择的答案不正确。 @P_J_ 在 cmets 中为您提供了正确答案。
  • 谢谢大家,这个问题是重复的。经过这么多有用的讨论,添加答案几乎是明确的。 Sting 文字大部分时间都存储在一个特殊的“只读和静态”区域,当然这取决于平台。并且静态部分是确定的(只读不确定)。

标签: c malloc libcurl


【解决方案1】:

这些字符串文字在编译时被放置在可执行文件的静态只读部分中。它们与堆或堆栈是分开的。该函数只是返回一个指向这些字符串的指针。

参考

这是特定于平台和编译器的实现,但 C11 标准在第 6.4.5 节对此有一些相关要求。

在翻译阶段 7,一个字节或零值代码被附加到每个多字节 由一个或多个字符串文字产生的字符序列。多字节字符 然后使用序列来初始化静态存储持续时间和长度的数组 足以包含序列。

所以我们知道它必须在编译时存储在静态位置。

如果程序试图修改这样的数组,行为是 未定义。

这告诉我们数据必须是只读的。

编辑

有些人抱怨这是不正确的,引用了特定的平台或架构。如上所述这是特定于平台和编译器的

某些平台可能不支持只读数据,但编译器几乎肯定会尝试阻止您对其进行修改。由于行为未定义,意图是您永远不会这样做,因此对于所有意图和目的,数据都是只读的。

在问题的上下文中,这个答案是正确的。

【讨论】:

  • 谢谢,看来 c 和 java 一样,字符串字面量比较特殊。
  • 是的,大多数语言似乎至少有一些字符串的特殊行为。
  • 这是一个非常糟糕的不精确答案,只是重复有关字符串文字的神话。字符串文字不必放置在 RO 内存中,并且它们不必在它们使用的范围之外有效。任何哈佛架构的计算机都会先将其复制到数据存储器中。流行的例子是 uC 的 AVR 系列。非常受欢迎的系列,例如用于 Arduino 板。
  • 最后一句也是错的。它只是说我们不能修改它。如果我们修改它,程序行为是没有定义的。而已。您对标准文件的非常幼稚的解释是错误的
  • 这个答案在最重要的地方是正确的:保证静态存储持续时间,用户必须将文字视为只读。所有部分内容和堆栈/堆内容都是实现定义的,与实际回答无关。我可能会使用不同的措辞,但总的来说答案很好。
【解决方案2】:

根据 C 标准(6.4.5 字符串字面量,第 6 段),字符串字面量具有静态存储持续时间:

一个字节或零值代码被附加到由一个或多个字符串文字产生的每个多字节字符序列。然后使用多字节字符序列来初始化一个静态存储持续时间数组 […]

这意味着它们的内存,无论它在物理上是什么,都可以保证比函数返回的寿命更长,并且指向该内存的指针仍然有效。

因此,您将返回一个指向内存位置的指针,该内存位置保证有效,并且包含字符串文字给出的值。

【讨论】:

  • 这里的问题是我们在这个线程中说找不到明确的声明来断言你所说的。你能粘贴来自 ISO9899 的明确声明,说明你所说的话吗?
  • @alinsoar 添加了报价,尽管我相信它为这个答案增加了零值:根据我给出的参考找到这个报价是微不足道的。此外,投票率最高的答案已经包含了准确的引用(虽然我现在才看到,而且那个答案也包含错误)。
  • 我在 ISO9899 中看到了该声明,我不确定 used to initialize an array of static storage duration 是否被正确解释为“将字符串保留在静态区域”。
  • @alinsoar 还有什么其他的方式来解释它?它确实在那里说。如果你看到编译器做了不同的事情,那么编译器是在as-if rule 下运行的。但堆栈分配只有在编译器能够证明函数退出后不存在对内存的引用时才会发生。
  • @alinsoar:检查汇编代码只会向您展示 C 实现如何实现代码。由于 C 标准的“好像”规则,允许编译器生成任何希望得到相同结果的代码。如果该程序不依赖函数返回后存在的字符串,则编译器可以生成仅在堆栈上或作为指令中的立即数具有该字符串的代码,因为 该程序中 的结果是相同。因此编译器优化了该程序的代码。这不会改变 C 标准指定的语义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 2019-05-04
  • 2017-02-19
  • 1970-01-01
相关资源
最近更新 更多