在函数参数中将字符串字面量转换为char*是否合适?

3

我有一个函数,它接收一个char *参数:

Foo::Foo (char * arg0) {
    ....
}

在原始示例中,使用char[]来传递此值...
char bar[] = "Bar";
Instance.foo (bar);

...这很好用。

但是,我发现我可以传递一个字符串字面量,强制转换为char *,而编译器不会发出任何警告。

Instance.Foo ((char *) "Bar");

然而,根据我的阅读,似乎应该避免这种情况——指向的内存值可能会发生变化。
上述陈述是否正确(“应该避免”),或者在这种情况下是否适当?

编辑 - 进一步的研究发现这篇文章 很好地回答了我的问题...


如果你百分之百确定该函数不会修改它,并且无法更改函数的签名以显示它,那么const_cast是一个选项。否则,我建议将其复制到新缓冲区中。 - chris
你为什么不使用 std::string 呢?这样就不会有这些问题了。 - Xymostech
2
最好将函数签名更改为接受char const * - Kerrek SB
@Steve,使用更好的类型有点烦人。std::string没有任何关于char *的内容,而std::vector可以,但不包括字符串函数。 - chris
这是在WNDCLASSEX中需要LPCTSTR的类名(msdn.microsoft.com/en-us/library/windows/desktop/…)。我正在尝试使用稍微改写了签名的教程。 - Ben
显示剩余4条评论
2个回答

10

是的,请避免这样做。如果您的函数使用了const char *,那么使用字符串字面值调用它没有问题。

C++编译器仅支持字符串字面值转换为char *以保持向后兼容性,但写入字符串字面值会导致未定义行为。

当您执行char bar[] = "Bar";时,您正在进行一项根本不同的操作(即使用值为{'B','a','r','\0'}的4个字符初始化数组),您可以自由地修改其值,而在执行char bar* = "Bar";时,则创建了一个指向4字节字符串的非const指针,您不能修改其值。

我认为,您永远不应该直接将字符串字面值转换为char*,而应该将其放入const char*中,然后(如果要与旧版API通信)显式地const_cast<char*>const属性,并附有一条注释说明您正在与确保不更改char的旧版API通信。这样可以搜索程序中的const_cast,以查找API是否已升级,或者想要查找涉及写入char*的段错误的来源。

您甚至可以使用const char*版本来包装旧版API,这些版本会在内部执行const_cast

最糟糕的情况是有一堆char*挂在那里,其中一些可写,其他的来自字符串字面值。


1

几乎应该避免这样做,只有在必须与损坏的旧API接口交互时才可以这样做,并且只有在查看了它们的源代码并确保它们没有写入字符串后才能这样做。

在传递之前,请使用strcpy复制字符串以确保安全。

什么是邪恶的?向字符串文字中写入是未定义的行为。


“Writing to string literals is undefined behavior” - 不确定你的意思 - 你能详细解释一下吗? - Ben
@Steve,字符串字面量存储在只读内存中。试图修改只读内存是不好的。未定义行为部分只是意味着语言不负责编译器决定要做什么。如果愿意,它甚至可以格式化您的硬盘。 - chris
啊。又有一束光照亮了云层。谢谢 - 是时候回到书本上了。 - Ben
3
Steve提到字符串字面量可能会被存储在只读内存中,或者受到编译器优化的影响。对它们进行写操作将导致未定义的行为。如果你不理解这个术语,建议阅读https://dev59.com/63E95IYBdhLWcg3wPbZ7。 - pmr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接