字符签名的最大副作用。 (对角色和演员表的签名效果的说明)

时间:2010-02-03 15:05:03

标签: c++ debugging casting signedness

我经常使用在C ++中使用字节时使用char的库。另一种方法是将“Byte”定义为unsigned char,但这不是他们决定使用的标准。我经常将C#中的字节传递给C ++ dll并将它们转换为char来处理库。

当向其他简单类型转换为字符或字符时,可能会出现一些副作用。具体来说,什么时候你已经处理了这个破碎的代码,你是怎么发现它是因为char签名?

幸运的是我没有在我的代码中碰到这个,在学校的嵌入式系统类中使用了一个char签名的转换技巧。我希望更好地理解这个问题,因为我觉得这与我正在做的工作有关。

8 个答案:

答案 0 :(得分:4)

如果您需要移动字节,则存在一个主要风险。有符号的char在右移时保持符号位,而unsigned char则不然。 这是一个小测试程序:

#include <stdio.h>

int main (void)
{
    signed char a = -1;
    unsigned char b = 255;

    printf("%d\n%d\n", a >> 1, b >> 1);

    return 0;
}

它应该打印-1和127,即使a和b以相同的位模式开始(给定8位字符,使用算术移位的2位补码和有符号值)。

简而言之,您不能完全依赖轮班对有符号和无符号字符的工作,因此如果您需要可移植性,请使用unsigned char而不是charsigned char

答案 1 :(得分:2)

当您需要在实现协议或编码方案时将char的数值与十六进制常量进行比较时,会出现最明显的问题。

例如,在实施telnet时,您可能希望这样做。

// Check for IAC (hex FF) byte
if (ch == 0xFF)
{
    // ...

或者在测试UTF-8多字节序列时。

if (ch >= 0x80)
{
    // ...

幸运的是,这些错误通常不会存在很长时间,因为即使是在带有签名char的平台上进行的最粗略测试也应该揭示它们。可以使用字符常量修复它们,将数字常量转换为char或将字符转换为unsigned char,然后比较运算符将两者都提升为int。但是,将char直接转换为unsigned将不起作用。

if (ch == '\xff')               // OK

if ((unsigned char)ch == 0xff)  // OK, so long as char has 8-bits

if (ch == (char)0xff)           // Usually OK, relies on implementation defined behaviour

if ((unsigned)ch == 0xff)       // still wrong

答案 2 :(得分:1)

最令我烦恼的是:

typedef char byte;

byte b = 12;

cout << b << endl;

当然是化妆品,但是...... ...

答案 3 :(得分:1)

我在编写搜索算法时被char签名所困,该搜索算法使用文本中的字符作为状态树的索引。我在将字符扩展为更大的类型时也会遇到问题,并且符号位传播会导致其他地方出现问题。

当我开始得到奇怪的结果时,我发现了,并且在初始开发过程中搜索除了我使用的文本之外的文本产生的段错误(显然,值> 127或<0的字符会导致这种情况,并且不一定会出现在典型的文本文件中。

使用变量时,请务必检查变量的签名。一般来说,我现在签署了类型,除非我有充分的理由,否则必要时进行投射。这非常适合在库中无处不在地使用char来简单地表示一个字节。请记住,char的签名未定义(与其他类型不同),您应该给予特殊处理,并注意。

答案 4 :(得分:0)

  

在将字符或字符转换为其他简单类型时

关键点是,将一个有符号值从一种基本类型转换为另一种(更大)类型不保留位模式(假设为二进制补码)。位模式0xff的带符号字符为-1,而带小数值-1的带符号短字为0xffff。但是,将值为0xff的unsigned char转换为unsigned short,会产生0x00ff。因此,在将类型转换为更大或更小的数据类型之前,请始终考虑正确的签名。 如果您不需要,请勿在签名数据类型中携带未签名数据 - 如果外部库强制您这样做,请尽可能晚地进行转换(或者如果外部代码尽可能早地进行转换)充当数据源。)

答案 5 :(得分:0)

编译多个平台时,你会失败,因为C ++标准没有将char定义为某个“签名”。

因此,GCC引入-fsigned-char-funsigned-char选项来强制执行某些行为。例如,可以在here找到有关该主题的更多信息。

修改

当您询问代码损坏的示例时,有很多可能会破坏处理二进制数据的代码。例如,您处理8位音频样本(范围-128到127)的图像,并且您希望将音量减半。现在想象一下这个场景(天真的程序员假设char == signed char):

char sampleIn;

// If the sample is -1 (= almost silent), and the compiler treats char as unsigned,
// then the value of 'sampleIn' will be 255
read_one_byte_sample(&sampleIn);

// Ok, halven the volume. The value will be 127!
char sampleOut = sampleOut / 2;

// And write the processed sample to the output file, for example.
// (unsigned char)127 has the exact same bit pattern as (signed char)127,
// so this will write a sample with the loudest volume!!
write_one_byte_sample_to_output_file(&sampleOut);

我希望你喜欢那个例子;-)但说实话,我从来没有真正遇到过这样的问题,就我记忆而言,甚至不是初学者......

希望这个答案对你们来说足够了。简短评论怎么样?

答案 6 :(得分:0)

C和C ++语言规范定义了3种用于保存字符的数据类型:charsigned charunsigned char。后两种问题已在其他答案中讨论过。我们来看看char类型。

标准表示char数据类型可以签署无符号,并且是实施决策。这意味着某些编译器或编译器版本可以以不同方式实现char。这意味着char数据类型不利于算术或布尔运算。对于算术和布尔运算,signed的{​​{1}}和unsigned版本可以正常工作。

总之,char数据类型有3个版本。 char数据类型适用于保留字符,但不适用于跨平台和翻译器的算术,因为 signedness 是实现定义的。

答案 7 :(得分:0)

签署扩展名。我的URL编码函数的第一个版本生成了类似“%FFFFFFA3”的字符串。