2

我写了一个简单的c代码,如下所示。在此代码片段中,我想验证 const 字符串的abcd存储位置。我首先猜测它应该存储在.data只读部分中。然而,在 Debian 中进行测试后,事情与我最初的猜测不同。通过检查 gcc 生成的汇编代码,我发现它被放置在 function 的堆栈框架中p。但是当我稍后在 OSX 中尝试时,该字符串.data再次存储在部分中。现在我对此感到困惑。有没有存储 const 字符串的标准?

#include<stdio.h>
char *p()
{
    char p[] = "abcd";
    return p;
}

int main()
{
    char *pp = p();
    printf("%s\n",pp);
    return 0;
}

更新:rici 的回答唤醒了我。在 OSX 中,初始文字被存储在.data之后,然后移动到函数的堆栈帧中。因此,它成为此函数的局部变量。但是,Debian 中的 gcc 处理这种情况与 OSX 不同。在 Debian 中,gcc 直接将文字存储在堆栈中,而不是从.data. 我很抱歉我的粗心。

4

2 回答 2

1

在您的情况下,它位于堆栈中。并将指针返回到 main 将导致未定义的行为。但是,如果您有static char p[] = "abcd";char *p = "abcd";它们(数据)位于 .data 中。

于 2014-09-18T17:02:19.827 回答
0

两者之间存在巨大差异:

const char s[] = "abcd";

const char* t = "abcd";

其中第一个声明s为从字符串“abcd”初始化的数组对象。s将具有与程序中任何其他对象不同的地址。字符串本身可能是编译时工件;初始化是一个副本,因此如果编译器可以找到执行初始化的其他方式(例如存储立即操作),则字符串不需要在运行时出现。

第二个声明声明t为指向字符串常量的指针。字符串常量现在必须在运行时出现,因为像t+1字符串中的指针这样的表达式是有效的。语言标准不保证程序中字符串文字的每一次出现都是唯一的,也不保证所有出现都被合并(尽管好的编译器会尝试做第二次。)但是,它保证它们具有静态生命周期.

因此,这是未定义的行为,因为数组的生命周期s在函数返回时结束:

const char *gimme_a_string() {
  const char s[] = "abcd";
  return s;
}

但是,这很好:

const char *gimme_a_string() {
  const char *s = "abcd";
  return s;
}

还:

const char s[] = "abcd";
const char t[] = "abcd";
printf("%d\n", s == t);

保证打印0,而

const char* s = "abcd";
const char* t = "abcd";
printf("%d\n", s == t);

可能会打印01,具体取决于实现。(如所写,它几乎肯定会打印1。但是,如果两个声明位于不同的编译单元中并且 lto 未启用,则很可能会打印0。)

由于数组形式是使用副本初始化的,因此非常量版本很好:

char s[] = "abcd";
s[3] = 'C';

但是 char 指针版本必须是 aconst以避免未定义的行为。

// Will produce a warning on most compilers with compile option -Wall or equivalent
char* s = "abcd";
// *** UNDEFINED BEHAVIOUR *** Can cause random program breakage
s[3] = 'C';

从技术上讲,非 const 声明s是合法的(这就是编译器只发出警告的原因),因为它试图修改 UB 常量。但是您应该始终注意编译器警告;最好将声明/初始化视为错误,因为它是。

于 2014-09-18T17:28:25.787 回答