繁体   English   中英

将char添加为int会产生意外结果

[英]adding char as int gives unexpected result

我尝试做一些hex-bin / bin-hex转换并测试哪个函数会更快,但是在将'a'添加为整数时遇到了奇怪的错误。

#include <stdio.h>

/* convert bin to hex char [0-9a-f] */
static inline unsigned char ToHex4bits1(unsigned char znak)
//unsigned char ToHex4bits1(unsigned char znak)
    {
    znak &= 0x0F;
    switch(znak)
        {
        case 10: return 'a';
        case 11: return 'b';
        case 12: return 'c';
        case 13: return 'd';
        case 14: return 'e';
        case 15: return 'f';
        default: return znak + 48;  /// 48  0x30    '0'
        }
    }

/* convert bin to hex char [0-9a-f] */    
static inline unsigned char ToHex4bits2(unsigned char znak)
//unsigned char ToHex4bits2(unsigned char znak)
    {
    //unsigned char add = '0';
    int add = '0';  /// [0-9]; add value of '0' (65 0x41    '0')
    znak &=0x0F;
    if(znak > 9)  /// [a-f]; if `znak' <0x0a, 0x0f> /// just one comparison as `znak' cannot be bigger than 15 anyway (znak &=0x0F;)
        {
        add = 0x61;  /// 'a'; // 87 0x61    'a'
        }
    return znak + add;
    }

//-----------//
int main()
    {
    int i;
    //char z;
    int z; 

    printf("\nToHex4bits1(i)\n");
    for(i=0; i<16; i++)
        {
        z = ToHex4bits1(i);
        printf("%d\t%02x\t%c\n", z, z, z);
        }

    printf("\nToHex4bits2(i)\n");
    for(i=0; i<16; i++)
        {
        z = ToHex4bits2(i);
        printf("%d\t%02x\t%c\n", z, z, z);
        }
    return 0;
    }

当我运行它时$ gcc -o tohex4bits tohex4bits.c; ./tohex4bits $ gcc -o tohex4bits tohex4bits.c; ./tohex4bits我得到这个结果:

ToHex4bits1(i)
48  30  0
49  31  1
(...)
57  39  9
97  61  a
98  62  b
(...)
102 66  f
48  30  0
# which is what I expected

ToHex4bits2(i)
48  30  0
49  31  1
(...)
57  39  9
107 6b  k # that's where things get interesting; it's 10 too much ('k'-'a'==10)
108 6c  l
109 6d  m
110 6e  n
111 6f  o
112 70  p

# which is wrong

第二个函数ToHex4bits2()到底有什么问题,为什么加'a'(97 / 0x61)使其加'k'(107 / 0x6b)或'A'=>'K'?

让我们仔细看看ToHex4bits2函数:

static inline unsigned char ToHex4bits2(unsigned char znak)
//unsigned char ToHex4bits2(unsigned char znak)
    {
    //unsigned char add = '0';
    int add = '0';  /// [0-9]; add value of '0' (65 0x41    '0')
    znak &=0x0F;
    if(znak > 9)  /// [a-f]; if `znak' <0x0a, 0x0f> /// just one comparison as `znak' cannot be bigger than 15 anyway (znak &=0x0F;)
        {
        add = 0x61;  /// 'a'; // 87 0x61    'a'
        }
    return znak + add;
    }

如果znak的值大于9则添加值0x61'a' ASCII代码)。 如果znak是(例如) 11 (十六进制0xb ),则加法0xb结果为0x72 ,这是'r'的ASCII代码。要解决此问题,您应先从znak减去100xa )。

当然,您不应该使用幻数 如果您的意思是字符'a'这样 在代码本身中。

原因很简单。 如果znak是10,那么您想返回'a' ,但是您要返回'a'+10 因此,返回znak+add-10

但是,这给自己带来了极大的困难。 处处都有魔术常数,完成一项简单任务的代码极其复杂。 这样可以:

{
znak &= 0x0F;
if(znak > 9) 
    return znak + 'a' - 10;
else
    return znak + '0';
}

或者,如果您想更紧凑。 您显然不怕复杂的代码:

{
znak &= 0x0F;
return znak > 9 ? znak + 'a' - 10 : znak + '0';
}

您提到您正在尝试优化此代码。 我很难看到您如何才能做到这一点。 您可能最好对更大的块进行优化,以查看算法是否存在问题。 但是我们可以在第一个方面做些小事情,就是这样:

#define likely(x)      __builtin_expect(!!(x), 1) 
#define unlikely(x)    __builtin_expect(!!(x), 0) 
static inline unsigned char ToHex4bits1(unsigned char znak)
{
    {
    znak &= 0x0F;
    // Hint the compiler that the first branch is less likely, which
    // improves branch prediction
    if(unlikely(znak > 9)) 
        return znak + 'a' - 10;
    else
        return znak + '0';
    }
}

在这里阅读有关内容: https : //www.geeksforgeeks.org/branch-prediction-macros-in-gcc/

但是我认为最快的方法是这样的:

static inline unsigned char ToHex4bits1(unsigned char znak)
{
    const unsigned char ret[] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    return ret[znak & 0x0F];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM