【问题标题】:Do C++ developers commonly count on implicit casting?C++ 开发人员通常依赖隐式转换吗?
【发布时间】:2016-05-10 17:50:18
【问题描述】:

我被分配了将 Windows 程序移植到 OS X 的任务。最初是用 C++ 编写的,我很喜欢它,因为我不经常使用 C 系列语言,并且喜欢使用 Objective端口中的 C++。

但是,Windows 源代码做了一些奇怪的事情,我想知道这是否是一种标准做法。我们在 Windows 和 OS X 上使用的 API 期望一个特定的对象方法被传递一个无符号的 short。最初的 Windows 开发人员创建了以下函数来计算该值:

static unsigned short hashcode ( const char* value ) {
  int h = 0 ;
  unsigned long length = strlen ( value ) ;

  for ( int i = 0 ; i < length ; i++ ) {
    h = ( 31 * h ) + value[i] ;
  }    

  return h ;
}

请注意,虽然函数返回 unsigned short,但它返回的变量被声明为 int。我查看了文档,OS X 和 Windows 都将 unsigned short 定义为 2 个字节,将 int 定义为 4。

如果不考虑数据类型,传递给此函数的值会导致函数返回非常大的数字,在某些情况下会返回几十位数字。在一种情况下,我用另一种语言不那么严格的类型复制了算法,我得到了2081357292912430390912 的值。当我将上述函数包装在命令行实用程序中时,相同的字符串返回值40576,我猜是因为这是较长值的截断版本。

所以我有两个问题。首先,为什么,如果 hashcode 被声明返回一个 unsigned short 并且它实际上正在返回并且 int 没有编译器抱怨?这不就是严格数据类型声明的初衷吗?确保函数和方法接收和返回预期的数据类型?

其次,这种截断是标准做法吗?对我来说这似乎很奇怪,首先要利用隐式转换,但也没有评论告诉某人正在发生这种情况(而且我无权联系原始开发人员询问)。由于它没有被评论为“特殊”,也许它只是 C/C++ 中的标准习语?

【问题讨论】:

  • 什么是“自动投射”?那是矛盾的?要么投,要么不投。
  • 也许“隐式转换”是一个更好的术语? return hreturn (unsigned short) h?
  • 我认为您的意思是“隐式转换”而不是“自动转换”。在 C++ 中,强制转换是显式转换。
  • 请将此源代码提交给thedailywtf.com
  • @SamVarshavchik,为什么?这是一个 djb 哈希函数,还不错。

标签: c++ standards


【解决方案1】:

首先,为什么如果 hashcode 被声明为返回一个 unsigned short 并且它实际上是在返回并且 int 编译器不会抱怨?

因为可以隐式执行从intunsigned short 的转换

这不就是严格数据类型声明的初衷吗?确保函数和方法接收和返回预期的数据类型?

是的。这正是这里发生的事情。声明为返回 unsigned short 的函数返回 unsigned short,这是隐式转换的结果。

其次,这种截断是标准做法吗?

是的。

它没有在代码中使用强制转换明确的一个很好的原因是 C++ 有一组可以隐式执行的转换,以及一组可以显式执行的更大的转换。后一组包括一些潜在危险的转换,例如指针和整数之间的转换。除非需要显式强制转换,否则利用隐式转换可以防止意外执行一种危险的转换。

我确实看到此实现存在潜在问题,但这与您的问题无关。我认为最好不要详述,只是不要将我的回答误解为对该功能的认可。

【讨论】:

  • 我想我假设任何支持的隐式转换都将归入那些不会丢失数据的转换,例如intshort,而可以的转换丢失数据必须明确才能在没有编译器警告的情况下工作。当然,您的脚注引起了我的好奇心,请问您看到了什么潜在的问题?
  • @Chuck 使用错误的类型来存储strlen 的结果,在不需要的时候调用strlen,但重要的是乘法会导致整数溢出除了最短的字符串之外的任何东西,与隐式转换不同,它不需要做任何明智的事情。
  • 嗯,这个函数不会存在于端口中。 :)
  • 为了避免危险的转换,总是有boost::implicit_cast&lt;T&gt;(或roll-your-own)
  • 我不知道:将函数内部的每个类型更改为unsigned int 甚至unsigned short,它就会停止做愚蠢的未定义行为。给定截断,h 中的零点大于 unsigned short afaict: 但在哈希累加h=h&lt;&lt;6+h&gt;&gt;2+value[i]; 中添加一些混洗以混洗更多位。或者窃取 boost hash combine。
【解决方案2】:

我会继续假设您的意思是隐式转换而不是自动转换。根据我的经验,这种行为在包括 C++ 在内的许多语言中普遍存在。要回答您的第一个问题,只要在被分配的类型和被分配的类型之间存在转换序列,这不会导致编译器错误。

通常在条件语句中,人们会传入整数而不明确写 == 0!= 0

例子:

int count = 10;
while (--count); // runs 10 times

int test = 0;
if (test); // evaluates to false

test = 1;
if (test); // evaluates to true

test = -1;
if (test); // evaluates to true

这里有一些关于隐式转换的文档http://en.cppreference.com/w/cpp/language/implicit_conversion

【讨论】:

  • 我已经多次看到整数和指针类型用作布尔测试。我想我把它放在了一个不同的类别中。
  • 是的,它有不同的感觉,但是是相同的机制
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多