在C中将单个字符(十六进制数)转换为整数

时间:2015-02-01 22:35:29

标签: c integer hex character

因此,对于作业,我必须将字符(0 - F)转换为整数(0 - 15),0 - { {1}}工作正常,但如果给出任何字母,则会打印一个随机数:例如,对于9,它会C,而19则会返回D

这是我的方法:

20

起初我的if语句是这样的:

int char2int(char digit) {
    int i = 0;

    if (digit == 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9)
        i = digit - '0';
    else
    if (digit == 'A' || 'B' || 'C' || 'D' || 'E' || 'F')
        i = digit - '9';
    else
        i = -1;

    return i;
}

但这造成了一些错误。你可以告诉我我不太了解C.我当前的If声明有效,但我确定它不必要很长。

6 个答案:

答案 0 :(得分:4)

  

if(digit == 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9)

这不是条件表达式在C中的工作方式。

您需要将digit分别与每个数字进行比较

if (digit == '0' || digit == '1' || digit == '2' ...

或以聪明的方式做到:

if(digit >= '0' && digit <= '9')
                         ^^ not =<

请注意,我将'放在数字周围,因为您要将数字与字母0 进行比较,而不是数字(不同的数字请参见here所有ASCII字符值)。

答案 1 :(得分:1)

当你开始时,你走的是正确的道路,但是稍微走开了。试试这个

#include <ctype.h>
int char2int(char d) {
    if (!isxdigit(d)) {
        return -1;
        }
    if (isdigit(d)) {
        return d - '0';
        }
    return (tolower(d) - 'a') + 10;
    }

如果你更喜欢接近范围测试的方法,你可以这样做:

int char2int(char d) {
    if (d >= '0' && d <= '9') {
        return d - '0';
        }
    d = tolower(d);
    if (d >= 'a' && d <= 'f') {
        return (d - 'a') + 10;
        }
    return -1;
    }

答案 2 :(得分:1)

假设ASCII以下内容从字符(0-9,a-f,A-F)转换为相关的无符号整数(0-15)。任何其他字符也将转换为... 0-15范围内的某个随机值。垃圾进,垃圾出。

unsigned hexToUnsigned(char ch) {
    return ((ch | 432) * 239'217'992 & 0xffff'ffff) >> 28;
}

具有32位整数的CPU通常能够忽略0xffff&#39; ffff屏蔽。在我的机器上,编译器将此函数转换为:

hexToUnsigned PROC
movsx   eax, cl
or      eax,1B0h
imul    eax, eax, 0E422D48h
shr     eax, 1ch
ret     0
hexToUnsigned ENDP

另一种常见的方法是减少明显的操作(只有三个),返回无效字符的总垃圾(这可能没问题),但也需要除法(将其从最高点取出):

return ((ch | ('A' ^ 'a')) - '0') % 39;

为了说明编译器对除法的看法,他们(至少在x64上)将其变为倒数乘以得到乘积,然后再乘以并减去,如果你需要余数:

hexToUnsigned PROC
; return ((ch | ('A' ^ 'a')) - '0') % 39;
movsx   r8d, cl
mov     eax, -770891565
or      r8d, 32
sub     r8d, 48
imul    r8d
add     edx, r8d
sar     edx, 5
mov     ecx, edx
shr     ecx, 31
add     edx, ecx
imul    ecx, edx, 39
sub     r8d, ecx
mov     eax, r8d
ret     0
hexToUnsigned ENDP

答案 3 :(得分:0)

返回值不是随机的。每个ascii字符在内存中用值表示。每个ascii字符的值可以在。中找到 Ascii Table

其他响应会告诉您条件表达式的错误,但另一个错误是如果字符是A,B,C,D,E或F,则需要将其转换为int {{1这意味着取A,B,C,D,E或F的值减去最小值A,然后加到该值。

此外,您可以看到,如果您不需要字符的确切值,则可以在不使用ascii表的情况下使用字母连续的属性。

答案 4 :(得分:0)

如果您愿意将char等假设编码为ASCII和2的补码,则以下内容非常有效。

此代码不是为了提高可读性。如果需要考虑,请使用其他解决方案。这是为了严格编码。对于给定的处理器,它大约是10条指令。您的结果会有所不同。

减1.这使char值向下移动1.特别是,A-Z现在是64-89,a-z在96-121范围内。

测试一个位(64位)是否清除:在'0' - '9'的范围内。如果是这样,则增加7并使用掩码保持该位(64位)清零。

否则屏蔽一下以将a-z折叠到A-Z范围内。

现在'0'到'9'和'A'到'Z'处于连续范围内。只需减去54.除unsigned char0-9A-Z以外的所有a-z值都将具有值&gt; 35.这对任何以36为基础的基础用途都很有用。

int Value(char ch) {
  if (!(--ch & 64)) {       // decrement, if ch in the '0' to '9' area ...
    ch = (ch + 7) & (~64);  // move 0-9 next to A-Z codes
  } else {
    ch &= ~32;
  }  
  ch -= 54;                 // -= 'A' - 10 - 1
  if ((unsigned char)ch > 15) { 
    ; // handle error
  }
  return (unsigned char)ch;
}

答案 5 :(得分:0)

在redis中

https://github.com/antirez/redis/blob/3.2.8/src/sds.c#L892

int hex_digit_to_int(char c) {
    switch(c) {
    case '0': return 0;
    case '1': return 1;
    case '2': return 2;
    case '3': return 3;
    case '4': return 4;
    case '5': return 5;
    case '6': return 6;
    case '7': return 7;
    case '8': return 8;
    case '9': return 9;
    case 'a': case 'A': return 10;
    case 'b': case 'B': return 11;
    case 'c': case 'C': return 12;
    case 'd': case 'D': return 13;
    case 'e': case 'E': return 14;
    case 'f': case 'F': return 15;
    default: return 0;
    }
}