3

我想知道以下定义之间有什么区别:

// file.cpp:
namespace n
{
static char const * const str1 = "hello";
static char const str2[] = "hello";
}

我想要的行为,我认为它们都提供:

  • 它们都引用不可变数据(因为数据是 char consts)
  • 两个变量都不能修改(因为 str1 被定义为 * const 并且因为 str2 是一个数组,不能用作左值?)
  • 它们都有内部链接(通过静态)
  • 他们都有命名空间范围
  • 如果指向任一字符串数据的指针可用于不同的模块(通过此处未指定的某些函数),则这些字符串的内存将是有效的(str1 因为它指向字符串文字,而 str2 因为数组在命名空间中声明范围)

语言是否保证有任何差异?如果存在依赖于实现的行为,我如何调查不同平台上的差异?

(对于这个例子,我对将这些行为与 std::string 选项进行对比不感兴趣,尽管如果您认为其他读者会感兴趣,也可以随意谈论。)

4

3 回答 3

5

是的,有:一个仍然是数组,另一个是指针。而且指针和数组也不一样。

一个特定的方面可能是sizeof运算符的使用 - 对于指针,它不会导致字符串的长度,它会在数组上产生(当然,终止 NUL 字符也被计算在内)。

于 2013-06-11T18:42:24.523 回答
4

您可以很容易地遇到两者之间的差异,因为一个是数组,另一个是指针。例如,将评估和sizeof的不同(即不相关)值。另外,它们都是左值(是什么让你认为它们不是?),这意味着你可以应用它们并得到完全不同的结果n::str1n::str2&

&n::str1; // evaluates to a `char const *const *` value
&n::str2; // evaluates to a `char const (*)[6]` value

另请注意,第一个是指向某些不可变实现拥有的“字符串文字存储区”的直接指针,而第二个是“您”拥有的数组,通过从上述“字符串文字存储区”复制数据来初始化”。允许实现在整个程序中合并那些实现拥有的字符串文字。例如,您声明另一个使用相同字符串字面量初始化的指针

char const *str_another = "hello";

语言保证str_another不指向n::str2

assert(str_another != n::str2); // will not fail

但它不保证str_another不同于n::str1

assert(str_another != n::str1); // can fail
于 2013-06-11T18:50:22.720 回答
1

&n::str1是一个char const * const *,但是&n::str2是一个char const (*)[6]

您可以通过函数重载解析获得一些差异,但可能只有在其中一个重载使用对数组的引用类型时。

template<typename T>
void f(T); // #1

template<typename T, std::size_t N>
void f(T (&)[N]); // #2

void g() {
    f(n::str1); // calls #1, T is char const*
    f(n::str2); // calls #2, T is char const, N is 6.
}

此外,正如@H2CO3 指出的那样,sizeof(n::str1)sizeof(char const*),但是sizeof(n::str2)是 6。

于 2013-06-11T18:46:31.057 回答