适合在函数参数中将字符串文字转换为 char * 吗?

Posted

技术标签:

【中文标题】适合在函数参数中将字符串文字转换为 char * 吗?【英文标题】:Appropriate to cast string literal to char * in function argument? 【发布时间】:2012-10-20 10:23:27 【问题描述】:

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

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

在原始示例中,char[] 用于传递此值...

char bar[] = "Bar";
Instance.foo (bar);

...效果很好。

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

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

但是,根据我的阅读,似乎应该避免 - 指向的内存值可能会改变。

上述陈述是否正确(“应该避免”)或者在这种情况下是否合适?


编辑 - 进一步的研究出现了 this article,它很好地解决了我的问题......

【问题讨论】:

如果你 100% 确定函数没有修改它,并且你不能改变函数的签名来显示它,const_cast 是一个选项。否则,我会坚持将其复制到新缓冲区。 好的。那么我的理解是正确的,还是有不同的原因? 您有什么理由不使用std::strings?你不会有任何这些问题。 它起作用的原因是由于遗留问题,但修改字符串文字的内容是未定义的行为,所以你不希望这样。我希望来自 GCC 的 warning: deprecated conversion from string literal to char * 之类的东西。 最好将函数签名更改为接受char const * 【参考方案1】:

是的,避免这种情况。现在,如果你的函数使用了const char *,那么用字符串字面量调用它并没有错。

C++ 编译器仅出于向后兼容性的原因支持 char * 的字符串文字,写入字符串文字会导致未定义的行为。

当您执行 char bar[] = "Bar"; 时,您所做的事情与您执行 char bar* = "Bar"; 时(您正在创建一个非-const 指向你不能修改的 4 字节字符串的指针)。

在我看来,您永远不应该将字符串文字直接转换为 char*,而应将其放入 const char* 然后(如果您正在与旧版 API 通信)显式地 const_cast<char*> constness , 并附有评论说您正在与保证不会更改 chars 的遗留 API 交谈。这样做的好处是您可以在 API 升级时搜索您的程序以查找那些 const_casts,或者您想查找涉及写入 char* 的分段错误来自何处。

甚至可以使用 const char* 版本封装旧版 API,其中包含 const_cast

绝对最糟糕的情况是有一堆 char*s 闲逛,其中一些可写,其他来自字符串文字。

【讨论】:

【参考方案2】:

应该不惜一切代价避免这种情况,并且只有在您必须与损坏的旧 API 交互并且只有在您查看了它们的源代码并确保它们没有写入字符串时才能这样做。

请注意安全,并在传入之前使用 strcpy 复制字符串。

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

【讨论】:

Writing to string literals is undefined behavior - 不知道你的意思 - 你能扩大一点吗? @Steve,字符串文字存储在只读内存中。试图修改只读内存是不好的。未定义的行为部分仅意味着该语言不对编译器决定执行的任何操作负责。如果它愿意,它可以格式化你的硬盘。 啊。另一道光穿过云层。谢谢 - 是时候回到书本了。 @Steve 字符串字面量可能 存储在只读内存中或受编译器可以进行的任何优化的约束。写信给他们有未定义的行为。如果你对这个词有疑问,我建议阅读***.com/questions/2397984/…

以上是关于适合在函数参数中将字符串文字转换为 char * 吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 OCaml 中将 char 转换为字符串

如何在 C++ 中将字符串转换为 const char[]

在 C# 中将 char 转换为 int

在Java中将字符串转换为“字符”数组

将 System::String^ 转换为 unsigned char*

如何使用“ord”函数在 Haskell 中将 Char 转换为 Int?