可以在内置类型中使用C风格的强制转换吗?

时间:2009-02-09 12:43:53

标签: c++ casting

在这里阅读了很多关于C ++ C ++风格的答案后,我仍然有一个小问题。我是否可以对long x=(long)y;这样的内置类型使用C风格的转换,或者它仍然被认为是危险和危险的?

9 个答案:

答案 0 :(得分:28)

  

我可以对内置类型使用C风格的转换,例如long x =(long)y;或者它仍然被认为是危险和危险的?

永远不要使用它们。反对使用它们的原因也适用于此。基本上,一旦你使用它们,所有的赌注都会关闭,因为编译器不会再帮你了。虽然这对于指针而言比其他类型更危险,但它可能仍然危险并且在出现错误的情况下提供较差的编译器诊断,而新样式转换提供更丰富的错误消息,因为它们的使用受到更多约束:Meyers引用抛弃const ness的示例:使用除const_cast之外的任何演员都不会编译,从而明确 在这里发生的事情。

此外,无论类型如何,其他一些缺点也适用,即语法考虑:C风格的演员表非常不引人注目。这并不好:C ++强制转换在代码中很明显,并指向潜在危险的代码。它们也可以在IDE和文本编辑器中轻松搜索。尝试在大型代码中搜索C风格的演员表,你会发现它有多难。

另一方面,C风格的演员表没有优于C ++演员阵容的优势,所以甚至没有需要考虑的权衡。

更一般地说,Scott Meyers建议在Effective C ++中使用“最小化强制转换”(第27项),因为“强制转换会破坏类型系统。”

答案 1 :(得分:17)

我不会,原因如下:

  • 演员很难看,应该是丑陋的,并且在你的代码中脱颖而出,并且可以使用grep和类似工具找到。
  • “始终使用C ++强制转换”是一个简单的规则,更容易被记住和遵循,“使用C ++强制转换为用户定义的类型,但在内置类型上使用C风格的强制转换是可以的。 “
  • C ++样式转换为其他开发人员提供了有关为什么需要强制转换的更多信息。
  • C风格的强制转换可以让你进行你不想要的转换 - 如果你有一个接口(int *)并且你使用c风格的强制转换来传递一个const int *和接口更改需要花费很长时间*,使用c风格的演员表的代码将继续有效,即使它不是你想要的。

答案 2 :(得分:8)

如果你从一个数字类型 转换另一个数字类型,那么我认为C风格的强制转换首选到{{ 1}}。每个*_cast运算符都有一个特定的理由不在数字类型上使用它:

  • *_cast,当应用于数字类型时,执行正常的数字转换而不是重新解释位,即写reinterpret_cast 不会生成具有相同位数表示的整数作为那个浮点常数。这与直觉相反。
  • 在数字上永远不需要
  • reinterpret_cast<uint64_t>(3.14159),如果应用于数字变量(而不是指针或对数字的引用),表明该变量的类型不正确。
  • const_cast对数字没有意义,因为数字从不具有动态类型。
  • dynamic_cast通常用于类类型。因此,看起来很奇怪static_cast应用于数字;你的读者会抓挠他们的头脑,并想知道是否有一些他们不知道的关于static_cast的东西,当它应用于数字时,它会与C风格的演员之间的不同。 (事实上​​,它们是相同的,但我必须阅读相关的C ++规范部分,以确保确定它们是相同的,我仍然有“一些奇怪的东西必须在这里”反应。)

还有一个额外的风格理由来避免它们:

  • 如果需要在数字类型中进行转换,则可能需要在集群中执行其中的几个;因此,C风格演员的简洁很重要。例如,我现在正在编写的程序有很多这样的东西:

    static_cast

    在这里使用uint32_t n = ((uint32_t(buf[0]) << 24) | (uint32_t(buf[1]) << 16) | (uint32_t(buf[2]) << 8) | (uint32_t(buf[3]) )); 会模糊算术,这是重要的事情。 (注意:那些演员表只有在static_cast时才是不必要的,现在 是一个安全的假设,但我仍然更喜欢显性。)(是的,我可能应该把这个操作分解为{ {1}}内联帮助器,但我仍然以相同的方式编写代码。)

答案 3 :(得分:3)

我可以想到一个C风格演员的合法用法:

// cast away return value to shut up pedantic compiler warnings
(void)printf("foo\n");

答案 4 :(得分:2)

我认为根据具体情况可能没问题。例如:

/* Convert -1..1 to -32768..32767 */
short float_to_short(float f)
{
    return (short)(max(-32768.f, min(32767.f, f * 32767.f)));
}

答案 5 :(得分:2)

在我看来,当使用标准库函数和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&lt;&gt;()会更好,因为如果类型改变并且转换不再有意义,你可以确保编译器会出错。此外,如果您只使用c风格,则无法在代码中搜索强制转换。 “static_cast<mytype>(”非常容易搜索。 :)

答案 6 :(得分:0)

如果你发现你需要做一个C风格的演员(或者reinterpret_cast),那么仔细看看你的代码是99.99%确定它有问题。这些演员阵容几乎不可避免地要求实现特定的(通常是未定义的)行为。

答案 7 :(得分:0)

为什么你需要那个特定演员?任何数字类型都可以在没有强制转换的情况下转换为long(可能会丢失精度),因此强制转换不会让编译器执行任何已经无法执行的操作。通过强制转换,您所做的就是删除编译器发出警告是否存在潜在问题的能力。如果你要将其他基本类型(如指针)转换为long,我真的很想看到reinterpret_cast&lt;&gt;而不是C型演员阵容,所以如果结果出现问题,我可以轻松找到正在发生的事情。

我不会毫无理由地赞成施法,而且我肯定不会在没有充分理由的情况下批准C型演员。我没有理由在大多数内置类型之间进行投射,如果有的话,我希望能够通过文本搜索轻松找到它。

答案 8 :(得分:0)

我喜欢遗留C强制转换的一种情况是将字节缓冲区转换为不同的签名。许多API具有不同的约定,并且实际上没有“正确的答案”,并且在完成的上下文中,强制转换并不危险,其中代码只需要与所使用的库的组合一样是平台无关的。

我的意思是一个具体的例子,我认为这很好:

unsigned char foo[16];
lib1_load_foo(key);
lib2_use_foo((char*)key);

但是对于其他任何事情,如果需要施放,它将具有潜在的副作用,这应该是突出的,并且使用C ++风格(可以说是丑陋的)演员是正确的选择。如果不需要施放,则不要使用施法。