【问题标题】:Convert single Character (hex number) to Integer in C在C中将单个字符(十六进制数)转换为整数
【发布时间】:2015-03-31 20:50:48
【问题描述】:

所以对于一个作业,我必须将一个字符 (0-F) 转换为一个整数 (0-15),0-9 工作正常,但如果有任何字母是给定,它打印一个随机数:例如,对于C,它给出19,对于D,它返回20

这是我的方法:

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;
}

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

if (digit => 0 && =< 9)

if (digit => A && =< F)

但这给出了一些错误。你可以说我不太了解 C。我当前的 If 语句有效,但我确信它不必要地太长了。

【问题讨论】:

    标签: c integer hex character


    【解决方案1】:

    在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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      假设 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'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
      

      【讨论】:

      • 你是在故意阻止 OP 倾向于 C 吗?
      • @chqrlie,我正在尝试回答这个问题 - 如何将单个十六进制字符转换为整数 - 以我(希望其他人)在搜索后会很高兴找到的方式.
      • 你的小玩意儿的解决方案确实很有价值,但对于目前的 OP 技能水平来说太遥不可及了......
      【解决方案3】:

      如果你愿意假设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。除 0-9A-Za-z 之外的所有 unsigned char 值都将具有 > 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;
      }
      

      【讨论】:

        【解决方案4】:

        当你开始的时候,你走在正确的道路上,但有点偏离了方向。试试这个

        #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;
            }
        

        【讨论】:

        • 谢谢!这是有道理的,除了 d = tolower(d) 部分。你确定这会返回一个 Int 类型吗?
        • 我可以这样做吗:return (digit - 'a') + 10 使其返回 15 为例如 char F?
        • 您应该添加 10(我已将其添加到示例中)
        【解决方案5】:

        返回值不是随机的。每个 ascii 字符在内存中都由一个值表示。每个 ascii 字符的值可以在 Ascii Table.

        其他回复告诉你你在条件表达式上做错了什么,但另一个错误是如果字符是 A、B、C、D、E 或 F,你需要将它转换为 int 像这样i = ( digit - 'A' ) + 10这意味着取 A、B、C、D、E 或 F 的值减去 A 的最小值并加上 10。

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

        【讨论】:

          【解决方案6】:

          如果 (数字 == 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 字符值)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-08-12
            • 1970-01-01
            • 2015-04-30
            • 2015-11-29
            • 2010-10-16
            相关资源
            最近更新 更多