【发布时间】:2010-10-06 09:26:43
【问题描述】:
在这里阅读了很多关于 C++ 中 C 风格转换的答案后,我还有一个小问题。我可以对像 long x=(long)y; 这样的内置类型使用 C 风格的转换吗?或者它仍然被认为是坏的和危险的?
【问题讨论】:
在这里阅读了很多关于 C++ 中 C 风格转换的答案后,我还有一个小问题。我可以对像 long x=(long)y; 这样的内置类型使用 C 风格的转换吗?或者它仍然被认为是坏的和危险的?
【问题讨论】:
我可以对像 long x=(long)y; 这样的内置类型使用 C 风格的转换吗?或者它仍然被认为是坏的和危险的?
永远不要使用它们。反对使用它们的原因也适用于此。基本上,一旦你使用它们,所有的赌注都没有了,因为编译器将不再帮助你。虽然这对指针来说比其他类型更危险,但它可能仍然很危险,并且在出现错误的情况下提供较差的编译器诊断,而新样式转换提供更丰富的错误消息,因为它们的使用受到更多限制:Meyers引用了抛弃constness 的示例:使用除const_cast 之外的任何强制类型都不会编译,因此这里发生了什么 很清楚。
此外,无论类型如何,其他一些缺点都适用,即语法考虑: C 风格的强制转换非常不显眼。这不好:C++ 强制转换在代码中很明显,并指向潜在的危险代码。它们也可以在 IDE 和文本编辑器中轻松搜索。尝试在大型代码中搜索 C 风格的转换,您会发现这有多难。
另一方面,与 C++ 类型转换相比,C 风格的转换没有任何优势,因此甚至不需要考虑权衡。
更一般地说,Scott Meyers 建议在 Effective C++(第 27 条)中“最小化类型转换”,因为“类型转换颠覆了类型系统。”
【讨论】:
int convertDoubleToInt(double) 这样的函数会颠覆类型系统。但这几乎就是static_cast<int>(myDouble) 所做的。颠覆类型系统的是const_cast和reinterpret_cast,但不是其他两种类型。
我不会,原因如下:
【讨论】:
如果你将 from 转换为数字类型,to 另一种数字类型,那么我认为 C 样式转换 preferable 到 @987654321 @。每个*_cast 运算符都有一个特定的理由不在数字类型上使用它:
reinterpret_cast,当应用于数字类型时,会进行正常的数字转换,而不是重新解释位,即编写 reinterpret_cast<uint64_t>(3.14159) 不会产生与浮点常量具有相同位表示的整数。这与直觉相反。const_cast 在数字 value 上从来不需要,如果应用于数字 variable(与指针或对数字的引用相反),则表明该变量不正确。dynamic_cast just plain 对数字没有意义,因为数字从来没有动态类型。static_cast 通常用于类类型。因此,将static_cast 应用于数字看起来很奇怪;您的读者会摸不着头脑,想知道static_cast 是否有一些他们不知道的地方,这使得它在应用于数字时与 C 风格的演员表不同。 (事实上,它们是相同的,但我必须多次阅读相关的 C++ 规范部分才能确定它们是相同的,而且我仍然有“这里肯定发生了一些奇怪的事情”的反应.)还有一个避免它们的额外风格原因:
如果您需要在数字类型之间进行转换,您可能需要在一个集群中执行其中的几个;正因为如此,C 风格转换的简洁性很重要。例如,我现在正在编写的程序有一大堆这样的事情:
uint32_t n = ((uint32_t(buf[0]) << 24) |
(uint32_t(buf[1]) << 16) |
(uint32_t(buf[2]) << 8) |
(uint32_t(buf[3]) ));
在这里使用static_cast 会掩盖算术,这很重要。 (注意:只有在 sizeof(uint32_t) <= sizeof(unsigned int) 时才不需要这些强制转换,这 是 现在是一个安全的假设,但我仍然更喜欢明确性。)(是的,我可能应该将此操作分解为 be32_to_cpu内联助手,但我仍然会以相同的方式对其进行编码。)
【讨论】:
static_cast 相同用于数字类型之间的转换。
reinterpret_cast 意外隐藏为 C 样式转换。如果您要转换的类型是您认为是整数类型的指针,就会发生这种情况。嗯,写到我觉得我有点抓不住了……在我们开始讨论之前,我想在转换为数字类型时可能会发现更多潜在的程序员错误。现在我想我刚才描述的案例是唯一的。
static_cast 通常用于类类型。因此,将static_cast 应用于数字看起来很奇怪;" 这听起来像是个人期望,并没有似乎基于任何事实。
在我看来,在使用标准库函数和 STL 时对内置类型进行 C 样式转换是可以的,并且可以使代码更易于阅读。
在我工作的公司中,我们编译时会发出最多(4 级)警告,所以我们会收到关于每个小类型转换等的警告...... 所以我在这些中使用 c 风格的转换,因为它们很小,不是那么冗长且有意义。
for (int i = 0; i < (int)myvec.size(); i++)
{
// do something int-related with i
}
float val = (float)atof(input_string);
等等……
但是如果它的 on(例如库)代码可能会改变,那么 static_cast() 会更好,因为如果类型改变并且强制转换不再有意义,您可以确保编译器会出错。此外,如果您只使用 c 样式,则不可能在代码中搜索强制转换。 “static_cast<mytype>(”很容易搜索。 :)
【讨论】:
我能想到 C 风格转换的一种合法用途:
// cast away return value to shut up pedantic compiler warnings
(void)printf("foo\n");
【讨论】:
考虑到上下文,我认为这可能没问题。示例:
/* Convert -1..1 to -32768..32767 */
short float_to_short(float f)
{
return (short)(max(-32768.f, min(32767.f, f * 32767.f)));
}
【讨论】:
如果你发现你需要进行 C 风格的转换(或 reinterpret_cast),那么请非常仔细地查看你的代码,它 99.99% 肯定它有问题。这两种转换几乎都不可避免地导致特定于实现(并且通常是未定义的)行为。
【讨论】:
你为什么需要那个特定的演员表?任何数字类型都可以在没有强制转换的情况下转换为 long(可能会损失精度),因此强制转换不会让编译器做任何它已经不能做的事情。通过强制转换,您所做的只是消除编译器在存在潜在问题时发出警告的能力。如果您将其他一些基本类型(如指针)转换为 long,我真的很想看到 reinterpret_cast 而不是 C 类型转换,所以如果结果是我可以很容易地找到发生了什么成为一个问题。
我不会无缘无故地赞成强制转换,我当然也不会无故赞成 C 型强制转换。我认为没有理由在大多数内置类型之间进行转换,如果有的话,我希望能够通过文本搜索轻松找到它。
【讨论】:
我更喜欢传统 C 转换的一种情况是将字节缓冲区转换为不同的符号。许多 API 有不同的约定,并没有真正的“正确答案”,并且转换在它完成的上下文中并不危险,其中代码只需要与所使用的库的组合一样与平台无关。
我的意思是一个具体的例子,我认为这很好:
unsigned char foo[16];
lib1_load_foo(key);
lib2_use_foo((char*)key);
但是对于其他任何事情,如果需要强制转换,它会产生潜在的副作用,这应该很突出,使用 C++ 风格(可以说是丑陋的)强制转换是正确的选择。如果不需要强制转换,则不要使用强制转换。
【讨论】: