C++中的C风格类型转换和可读性

10

我知道在C++中不应该使用C风格的类型转换,但有些情况下,如果这样做,代码会更具可读性,比如下面这两个例子:

d = ((double)i * 23.54) / (d + (double)j);

d = (static_cast<double>(i) * 23.54) / (d + static_cast<double>(j));

哪一个更易读?

现在进入我的主要问题。显然我更喜欢上面的那个,但是我认为有一种方法可以使它更易读:

d = (double(i) * 23.54) / (d + double(j));

我的问题是,这样做是否更加低效?编译器在这种情况下是否会创建更多的double类型,比起其他强制转换方法呢?还是说它足够聪明,不需要这样做?这比典型的C风格强制转换更好还是更差?


2
在C++中,使用C++强制转换,并避免在C++对象上使用C风格的强制转换。虽然不是重复的问题,但与此有点相关:http://stackoverflow.com/questions/1635897/c-object-and-c-style-cast-question - DumbCoder
1
+1 很好的问题,我想我从来没有用过 double(i),我承认它非常易读。 - Stephane Rolland
3
"static_cast<...>" 更容易进行搜索。 - DanDan
6
如果ijint类型,ddouble类型,则不需要使用上面提到的任何转换。 - wilx
啊,我明白了。但是假设出于论证或可读性的需要呢?这是我举的一个不好的例子。 - DaedalusAlpha
5个回答

15

它们都不易读懂。你应该写成:

d = (i * 23.54) / (d + j);

1
@DaedalusAlpha:实际上,这并不重要。C++会为您进行转换并使用最合适的类型。这种解决方案的一个巨大优势是,如果您突然将“d”更新为“float”或“long double”类型,则编译器仍将执行最适当的转换,而您的显式转换将需要手动更改...有些可能会被遗忘。 - Matthieu M.
1
@DaedalusAlpha:我已经添加了一个答案,用于需要选择转换的情况(例如为了获得精度),简而言之,我强烈推荐使用boost::numeric_cast,因为它检查溢出/下溢并防止令人讨厌的未定义行为。 - Matthieu M.
3
@DaedalusAlpha: 使用强制类型转换“只是为了安全起见”,这往往会使人们在C++中使用强制类型转换时遇到麻烦:因为它们足够强大,可以执行不安全的转换,您可能会无意中创建一个表达式,当类型在其他地方被更改时,该表达式将从“过于冗长但正确”的状态静默地变为“可怕的、悲惨的错误”。 - Shog9
3
你的示例有问题并且明显存在漏洞。如果 RAND_MAXINT_MAX,那么在你将其转换为 double 类型之前,RAND_MAX+1 已经发生了溢出。将 1 替换为 1.0 可以修复该漏洞并删除无用的类型转换。 - R.. GitHub STOP HELPING ICE
1
@DaedalusAlpha:浮点类型总是优先于整数类型。(如果你仔细阅读我的评论,这实际上是暗示了的。)所有二进制算术和关系(<==等)运算符都以相同的方式操作,将小型参数“向上”转换。算术运算符的结果类型是在对它们进行任何转换后操作数的公共类型。%和位运算符的操作数必须是整数。 - j_random_hacker
显示剩余10条评论

4
编译器将“创建”完全相同数量的双精度数。将其强制转换为或构造原始数字类型之间没有实际区别。

1
虽然我非常感谢其他答案和这个帖子中得到的信息,但这是唯一回答了我的具体问题的答案,所以我会将其标记为答案 ;) - DaedalusAlpha

2

我已经在R的答案中评论了让编译器选择转换类型的内容,但仅限于这种特定情况。

然而,有些情况下您确实需要显式转换:

  • 您想防止溢出或增加精度
  • 您想检查转换的有效性

Boost Numeric Conversion提供了一种非常适合的转换方式,比static_cast好得多:boost::numeric_cast

  • 不需要检查时没有开销(例如从小整数到大整数的转换)
  • 在需要时运行时检查值(例如从大整数到小整数或从带符号数到无符号数的转换)

它比static_cast更易读,因为突出了数字的本质,并且比较安全,因为它可以防止未定义行为(和可移植性问题)发生。


你的版本即使修复了错误,仍然存在偏差。根据“n”的值,可能会有非常严重的偏差问题。 - R.. GitHub STOP HELPING ICE
@Matthieu:请阅读我在他发布的其他地方的示例中留下的评论。它是错误的。 - R.. GitHub STOP HELPING ICE
@Matthieu:不幸的是,那个片段包含了我试图避免的精确溢出错误... 这里再次呈现,已经更正: - j_random_hacker
在将double值乘以n后,每个int值下映射了多少个double值?如果n可以整除RAND_MAX+1,则映射是k = (RAND_MAX+1) / n到一的,且每个输出等可能出现(假设原始的rand()具有均匀分布)。但如果n不能整除RAND_MAX+1(最坏情况:n非常大,例如RAND_MAX),则某些输出将具有k个原像,而其他输出将具有k + 1 个原像。如果k为1且k + 1为2,甚至如果k为10且k + 1为11,则这种偏差非常糟糕... - R.. GitHub STOP HELPING ICE
@R.: 是的,但这种偏差对于O(1) RNG是不可避免的。(当n不能整除RAND_MAX+1时,需要使用一个while循环来丢弃一些值并重试。)这个公式仍然比rand() % n好得多,因为它的期望值仍然在n/2左右,因为更可能的结果尽可能均匀地分布,而对于rand() % n,更可能的结果都位于低端,所以它的期望值向下偏斜得非常强烈。 - j_random_hacker
显示剩余4条评论

2

在C ++中,强制类型转换函数之所以长而笨重,是经过设计的原因: 1)为了向用户表明他可能正在做错事 2)在必要时,引起注意那些可能正在执行危险或不寻常操作的代码片段。


1

在我看来,static_cast 更易读,因为它向读者提供了有关转换性质的信息。


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