2011-06-06 81 views
2

今天,我正在从开关块中得到一些奇怪的行为,特别是我正在从文件中读取一个字节,并将它与某些十六进制值(文本文件编码问题,没什么大不了)进行比较。代码看起来像这样:什么发生在整数类型转换的无符号字符的背景?

char BOM[3] = {0}; 
b_error = ReadFile (iNCfile, BOM, 3, &lpNumberOfBytesRead, NULL); 

switch (BOM[0]) { 
case 0xef: { 
    // Byte Order Marker Potentially Indicates UTF-8 
    if ((BOM[1] == 0xBB) && (BOM[2] == 0xBF)) { 
     iNCfileEncoding = UTF8; 
    } 
    break; 
      } 
} 

哪些没有工作,虽然调试看起来不错。我意识到交换机正在将值提升为整数,一旦点击就可以在case语句中使用0xffffffef进行匹配。当然,正确的解决方案是使BOM []无符号,现在一切都按照预期进行促进和比较。

有人可以简单地解释产生0xffffffef而不是0x000000ef的char - > int提升中发生了什么吗?

+2

无论是'char'工程作为'签署char'或'无符号char'是实现定义(这意味着该标准不会告诉你,但你的编译器的文档应该) 。正如你已经注意到的,如果你需要特别签名或未签名的角色,你需要指定你自己。 – 2011-06-06 20:50:10

+0

我现在非常清楚地看到,我被锁定在思考“无符号”的状态......即使当我意识到声明这样的解决方案时,我从来没有停下来认为239的字节值在签名变量中为负数。咄。感谢大家的意见。 – Stephen 2011-06-07 12:43:04

回答

1

“有人能简单介绍一下什么是 在焦炭回事? - > INT推广 所产生的,而不是 0x000000ef 0xffffffef”

与迄今为止的四个答案相反,它没有。

相反,您有负char值,其作为switch条件所要求的

C++ 98§6.4.2/ 2
晋升为相同的负int值 执行积分促销。

与32位的C++编译器 0xffffffef

然后,解释为unsigned int字面,因为它’ S对于一个32位的int过大,通过

C++ 98 2.13.1/2
如果它是八进制或十六进制和没有后缀,它具有第一这些类型中 其可以表示的:intunsigned intlong intunsigned long int。现在

,对于case标签,

C++ 98§6.4.2/ 2
积分常数表达式(5.19)的隐式转换为促进 类型的开关状态。

在你的情况,支持有符号目的地类型,则转换的结果是正式实现定义,通过

C++ 98§4.7/ 3
如果目标类型是如果在目标类型(和位域宽度)中可以表示 ,则值不变;否则,值为 实现定义。

但在实践中,几乎所有的编译器使用二进制补码表示没有捕获,因此实现定义的转换是在你的情况下,该位模式0xffffffef被解释为负值的补规范。你可以通过0xffffffef来计算哪个值 - 2 ,因为我们’在这里重新讲32位表示法。或者,因为这只是一个8位值,即’已被符号扩展为为32位,您可以选择将其计算为0xef - 2 ,其中0xef是字符代码点。

干杯&心连心,

3

您的(有符号)字符的符号被扩展为一个有符号整数。这是因为签名值以二进制形式存储的方式。

1以二进制INT二进制炭= 00000001

1 = 00000000 00000000 00000000 00000001

在二进制炭-1 = 11111111

二进制INT -1不是00000000 00000000 00000000 11111111但是11111111 11111111 11111111 11111111

如果你转换回十进制,你应该知道无论您是处理带符号值还是无符号值,都是因为11111111可能在签名时为-1,在无符号时为255。

3

char必须在平台上签字,你看到的是sign extension

+0

这绝对是简短的版本......谢谢。如果可以接受2个答案,那么这个答案也是一样。正如我所说,即使当我看到解决方案时,我也没有看到0xef是一个负值...伟大的隧道视野...再次感谢。 – Stephen 2011-06-07 12:48:22

2

什么还没有说明(因为我键入,无论如何)是没有说明char是否被烧焦。在你的情况中 - 如上所述 - char被签名,所以高于127的任何ASCII值将被解释为否定的。

相关问题