【问题标题】:What is the difference between two 'char*' castings in c++c ++中两个'char *'铸件有什么区别
【发布时间】:2016-02-25 06:59:51
【问题描述】:

我确实有一个“C”函数

find_register(char *name)

从“C++”例程中调用。调用它的第一个提示是

find_register("%ebx")

这会导致警告

deprecated conversion from string constant to 'char*'

好的,我更正了

find_register(string("%ebx").c_str())

这会导致错误消息

"invalid conversion from 'const char*' to 'char*'

最后,

find_register((char*)string("%ebx").c_str())

在没有错误消息和警告的情况下被接受。

我的问题: 1./错误消息的可能原因是更改“const char *”的可能性是开放的。没关系,但在第一种情况下,不太复杂的版本允许这样做,并且将字符串常量转换为 'char *' 是合法的,但不推荐使用的转换。有没有更深层次的原因?

2./ 有什么简单的方法可以做我想做的事吗? (对于程序员来说,完美的(编译器)代码很难读懂)

【问题讨论】:

  • 你要输入一个变量,find_register(char *name) 就可以了。但是你输入了一个文本,就不行了
  • find_register(string("%ebx").c_str()) 没有“纠正”,只是让问题变得更糟。
  • 我假设您不想更改在 find_register 函数中用作查找键的寄存器名称 - 那么为什么不告诉编译器呢?声明函数,使其接受“const char *”
  • @tofro 你说得对,但我在我的应用程序中调用了一个带有第三方字符串数组的第三方函数。

标签: c++ c casting constants


【解决方案1】:

原因在于 C++ 语言的原始根源,早在那个时候,与 C 的一定程度的向后兼容性被认为很重要。

在 C 语言中,字符串文字尽管是不可修改的,但具有 char [N] 类型。出于这个原因,它们可以隐式转换为 C 中的 char * 类型。在 C++ 中,字符串文字的类型为 const char[N]。形式上,const char[N] 不能隐式转换为 char *。但出于上述 C 兼容性原因,原始 C++ 规范 (C++98) 允许将字符串文字隐式转换为 char *。此例外仅针对直接字符串文字,作为提供给字符串文字的一种特殊处理形式。

但最终 C 兼容性问题变得不重要了,这种特殊处理在 C++03 中被弃用了。所以,这就是编译器告诉你的。在您的find_register("%ebx") 调用中,它同意将直接字符串文字转换为char *,但警告您不推荐使用此转换。在 C++11 中,这种隐式转换是完全禁止的。

在所有其他上下文中(不是直接字符串文字),将 const char [N]const char * 隐式转换为 char * 是被禁止的,并且一直是被禁止的。这就是为什么你的

find_register(string("%ebx").c_str())` 

variant 没有机会编译。

至于解决这个限制...如果您确定find_register(char *name) 不会尝试更改name 指向的数据(并且您不能只是将find_register 的参数类型更改为const char *name ),然后

find_register(const_cast<char *>("%ebx"))

是一个相当可接受的解决方案(附带适当的注释)。当然,如果find_register 是一个修改函数,那么你将不得不这样做

char reg[] = "%ebx";
find_register(reg);

【讨论】:

  • 感谢您的详细回答。实际上,我使用的是第 3 方代码,并将其改编为 C++。所以,实际上“%ebx”和“find_register(char *name)”对我来说都是“外来的”,我需要从 C++ 中使用它们。您对使用 'const_cast("%ebx")' 的建议在视觉上对我很有吸引力。
【解决方案2】:

函数find_register(char*)的原型表明它可能会改变参数,因为它只是一个传递的指针。您没有提及您是否拥有该函数的源代码,所以我假设您没有,否则最好将该函数更改为接受char const *,前提是它不会更改内容。

否则只传递一个可修改的数组:

char arg[] = "%ebx";
find_register(arg);

写:

find_register((char*)string("%ebx").c_str())

很危险,如果函数确实修改了字符串,例如strtok?但是如果你坚持至少尝试使用 C++ 风格的转换而不是 C 转换(在这种情况下是 find_register(const_cast&lt;char*&gt;("%ebx")))。

旁注:我个人觉得尽可能避免使用 C 方式放置 const 更容易阅读。因此,当指针恒定时,不要写 const char *char const *char * const,即 const 总是向左 - 它更一致。

【讨论】:

  • 我很确定(在这种情况下)它并不危险,因为该函数只进行表查找。关于旁注:一致性和可读性很重要,但会导致问题:'' 属于什么? (比如说,什么声明了 'char a,b;' 或 'char *a,b;')
  • @katang 我更喜欢在每一行写一个声明并将 ptr 符号放在类型附近,因为我发现它是类型的一部分。恕我直言,它使代码更清晰,更不容易出现 oops :-) 例如char* a; char b; 但这只是我个人的喜好。右侧的 const 也可以更好地使用 typedef。
【解决方案3】:

如果您将字符串文字传递给find_register(char *name),则函数原型应为find_register(const char *name),因为字符串文字不可修改。

通过这种转换,C++ 将很​​高兴让您自爆并尝试修改name,这给了我一个分段错误,如下面的代码:

void modifyIllegally(char* name) {
    name[0]='d';
}

int main() {
    modifyIllegally("abc");
}

编辑:如果您不控制 C 程序的 API 并确定它不会更改 char*,您可以使用编译器标志禁用此警告。对于 gcc,标志是 -Wno-write-strings

【讨论】:

  • 好的,正如我所写,我理解这种可能性。我的问题是为什么 C++ 编译器会以不同的方式处理那些基本相同的情况。
  • @katang 关键是它们非常不相同:字符串文字在内部是不可修改的:它是在编译时决定的,不能更改。以这种方式初始化 char* 是出于向后兼容的原因,但它本质上是不安全的,因此编译器会警告您。 C 永远不会让您以其他方式将 const char* 隐式转换为 char*,因此编译器甚至不会打扰您:它只是禁止它。
猜你喜欢
  • 1970-01-01
  • 2014-03-21
  • 2014-06-20
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 1970-01-01
  • 2014-05-03
  • 2020-10-08
相关资源
最近更新 更多