有人可以解释下面如何处理2个代码片段的区别吗?它们肯定会编译成不同的汇编代码,但我试图理解代码的行为方式可能不同。我理解字符串文字被抛入只读内存并且实际上是静态的,但是它与下面的显式静态有何不同?
struct Obj1
{
void Foo()
{
const char* str( "hello" );
}
};
和
struct Obj2
{
void Foo()
{
static const char* str( "hello" );
}
};
答案 0 :(得分:18)
使用静态版本时,只有一个变量存储在某处,每当执行该函数时,将使用完全相同的变量。即使是递归调用。
非静态版本将存储在堆栈中,用于每个函数调用,并在每次调用后销毁。
现在你的例子在编译器的实际操作方面有点复杂,所以让我们先看一个更简单的案例:
void foo() {
static long i = 4;
--i;
printf("%l\n", i);
}
然后是这样的主要内容:
int main() {
foo();
foo();
return 0;
}
将打印
3
2
而
void foo() {
long i = 4;
--i;
printf("%l\n", i);
}
它会打印
3
3
现在您的示例中有一个const,因此无法更改值,因此编译器可能会播放一些技巧,而它通常对生成的代码没有影响,但有助于编译器发现错误。然后你有一个指针,并且注意静态对指针本身有影响,而不是它指向的值。因此,您的示例中的字符串“hello”很可能会被放置在二进制文件的.data段中,并且只要程序存在一次就可以存活,与静态事物无关。
答案 1 :(得分:10)
本地静态变量首次 初始化 时遇到其定义,但 未被破坏 功能退出。因此 在函数的调用之间保持其值 。
在const
的情况下,这并不是所有有用的 - 至少,只要构造常量值在性能方面与地址的赋值一样可忽略不计。 (如果const
对象不是常量表达式,或者表达式需要相当多的资源来创建 - 就像在const Foo bar = foobar();
中foobar()
可能需要相当长的时间 - ,差异可能会变得很重要。 )
它确实产生影响的地方是当你想要为每个引用或指针返回对象时:除非它是本地静态对象,否则不能返回指向本地对象的引用或指针。 (感谢Matthieu指出这一点。)然而,当你想要使用它时,你需要记住,本地静态本质上是线程不安全的。
答案 2 :(得分:8)
我发现有些编译器对这两种编译器的处理方式不同。
带const char *
的版本会将数据从只读位置复制到堆栈上的变量。
static const char *
版本引用只读位置的数据(不执行复制)。
我在使用调试器逐步执行函数的汇编代码时发现了这种差异。我建议您打印汇编代码或在汇编语言级别使用调试器逐步查找确切的事实。
答案 3 :(得分:2)
虽然存在技术差异,但在使用和效果方面,您的两个示例是相同的。
更详细地说,您对static
关键字的使用适用于指向字符串文字的指针,而不适用于字符串文字本身。示例1中的指针将放在堆栈上,示例2中的指针将放置静态变量。
如果他们不同时对同一件事进行优化,我会感到惊讶。