【问题标题】:How to manually convert decimal value to hexadecimal string in C?如何在C中手动将十进制值转换为十六进制字符串?
【发布时间】:2011-07-11 00:44:38
【问题描述】:

n.b.我知道以前在 StackOverflow 上曾以各种不同的方式和情况提出过这个问题,但是寻找我寻求的答案并不能完全帮助我的具体情况。因此,虽然这最初看起来像 How can I convert an integer to a hexadecimal string in C? 这样的问题的重复,但给出的答案是准确的,但对我没有用。

我的问题是如何手动将十进制整数转换为十六进制字符串。我知道 stdlib.h 和 printf 有一些节拍技巧,但这是一项大学任务,我需要手动完成(教授的命令)。但是,我们可以寻求帮助。

使用良好的旧“除以16并将余数转换为十六进制并反转值”获取十六进制字符串的方法,但我的代码中肯定有一个大错误,因为它不是还给我,例如十进制值“188”的“BC”。

假设算法永远不需要为大于 256(或 FF)的小数找到十六进制值。虽然参数的传递可能不是最佳的或不可取的,但这是我们被告知要使用的(尽管我可以修改 getHexValue 函数,因为我自己编写了那个函数)。

这是我目前所拥有的:

/* Function to get the hex character for a decimal (value) between
 * 0 and 16.  Invalid values are returned as -1.
 */
char getHexValue(int value) 
{
   if (value < 0) return -1;
   if (value > 16) return -1;
   if (value <= 9) return (char)value;
   value -= 10;
   return (char)('A' + value);
}


/* Function asciiToHexadecimal() converts a given character (inputChar) to
 * its hexadecimal (base 16) equivalent, stored as a string of
 * hexadecimal digits in hexString. This function will be used in menu
 * option 1.
 */
void asciiToHexadecimal(char inputChar, char *hexString)
{
   int i = 0;
   int remainders[2];
   int result = (int)inputChar;
   while (result) {
      remainders[i++] = result % 16;
      result /= (int)16;
   }
   int j = 0;
   for (i = 2; i >= 0; --i) {
      char c = getHexValue(remainders[i]);
      *(hexString + (j++)) = c;
   }
}

char *hexString 是指向我需要输出到屏幕(最终)的字符串的指针。我需要转换为十六进制的char inputChar 参数(这就是为什么我不需要转换超过 256 的值)。

如果有更好的方法来做到这一点,它仍然使用void asciiToHexadecimal(char inputChar, char *hexString) 函数,我全神贯注,除此之外,我的调试似乎表明值没问题,但输出就像\377而不是预期的十六进制字母数字表示。

抱歉,如果问题本身(或代码)有任何术语或其他问题,我对 C 世界还是很陌生。

更新: 我突然想到,发布我显示值的方式可能与它的打印有关,而不是错误的转换。这里是:

char* binaryString = (char*) malloc(8);
char* hexString = (char*) malloc(2);
asciiToBinary(*(asciiString + i), binaryString);
asciiToHexadecimal(*(asciiString + i), hexString);
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString);

(除hexString 外,此代码片段中的所有内容都有效)

【问题讨论】:

  • +1 表示一个很好的问题并在寻求帮助之前为作业付出了很多努力 - 我希望更多 homework 问题具有类似的质量。
  • .. 以及对 输出 的出色思考!
  • "输出像 \377" -- \377(char)-1。您的 getHexValue 例程返回一个负整数作为错误代码,但键入时返回一个 char,然后您永远不会检查错误代码 - 这是双重错误。
  • 您的代码中没有任何强制转换是必需的。不必要的强制转换是个坏主意,因为它们可以隐藏错误。

标签: c hex decimal


【解决方案1】:

您已经很接近了 - 进行以下两个小更改,它会运行良好,您可以完成它:

(1)变化:

if (value <= 9) return (char)value;

到:

if (value <= 9) return '0' + value;

(您需要将 0..9 值转换为字符,而不仅仅是强制转换)。

(2) 变化:

void asciiToHexadecimal(char inputChar, char *hexString)

到:

void asciiToHexadecimal(unsigned char inputChar, char *hexString)

(inputChar 被视为已签名,这给% 带来了不良结果。

几个提示:

  • 对于无效输入,让 getHexValue 返回 '?' 而不是 -1(使调试更容易)

  • 编写用于调试的测试工具,例如

    int main(void)
    {
        char hexString[256];
    
        asciiToHexadecimal(166, hexString);
    
        printf("hexString = %s = %#x %#x %#x ...\n", hexString, hexString[0], hexString[1], hexString[2]);
    
        return 0;
    }
    

【讨论】:

  • 感谢您的回答,非常感谢,但我无法更改 asciiToHexadecimal 的签名。 :)
【解决方案2】:
char getHexValue(int value)
{
   if (value < 0) return -1;
   if (value > 16) return -1;
   if (value <= 9) return (char)value;
   value -= 10;
   return (char)('A' + value);
}

您可能希望为您感兴趣的每个值打印出调用此例程获得的字符。:)(printf(3) 格式 %c。)

当您使用 0 到 9 之间的数字调用 getHexValue() 时,您会返回一个介于 ASCII 控制字符范围内的 0 到 9 之间的数字。当您使用 10 到 15 之间的数字调用 getHexValue() 时,您会返回 ASCII 字母范围内的 65 到 75 之间的数字。

布道?如果您在编写代码的同时编写测试,Unit testing 可以为您节省 小时 时间。

有些人喜欢先写测试。虽然我从来没有长期坚持这种方法的纪律,但知道你必须编写测试将迫使你编写更容易测试的代码。而更容易测试的代码是less coupled(或“更解耦”),这通常会导致更少的错误!

尽早并经常编写测试。 :)

更新:在您包含输出代码后,我也不得不对此发表评论:)

char* binaryString = (char*) malloc(8);
char* hexString = (char*) malloc(2);
asciiToBinary(*(asciiString + i), binaryString);
asciiToHexadecimal(*(asciiString + i), hexString);
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString);

hexString 被分配了一个字节太小而不能成为 C 字符串——您忘记为 ASCII NUL '\0' 字符留出空间。如果您使用%c 格式说明符打印hexString,或者使用memcpy(3) 构建更大的字符串,则可能没问题,但您的printf() 调用将hexString 视为字符串。

一般来说,当你看到一个

char *foo = malloc(N);

打电话,害怕——C的成语是

char *foo = malloc(N+1);

+1 是您向他人(以及您自己,在两个月内)发出的信号,表明您已为 NUL 留出了空间。如果你在另一个计算中隐藏了+1,你就失去了记住每次阅读代码时都能捕捉到这些错误的模式的机会。 (老实说,就在两天前,我在 SO 上通过这种确切的模式找到了其中之一。:)

【讨论】:

  • 这很好,感谢您抽出宝贵时间帮助我找到错误。我想我看到了你的理解,我会做出适当的改变。至于单元测试,我非常喜欢在 C# 和 Ruby/Rails 中进行单元测试,我的大部分经验都来自这些地方,但我不知道如何围绕这个 C 代码封装一个测试框架,它的基础是提供给我们的从我们的教授那里,并告诉不要改变。最后,关于malloc(N+1); 的想法;我喜欢这个。我以前没有考虑过,你说得对,它更容易阅读。谢谢! :)
  • 哇!我得到了它的工作,感谢您的指点(哈哈,请原谅双关语!) - 我还发现了 for (i = 2; i &gt;= 0; --i) { 行的另一个错误,应该是 for (i = 1; i &gt;= 0; --i) { :) 但是,我再次对其进行了测试,并且它工作得很好!谢谢。
  • @Ash,哈!对不起,我错过了那个。不过,恭喜。 :)
  • 单元测试很有帮助,但首先以自然和可读的风格编写代码也是如此,例如return c &lt; 10? c + '0' : c - 10 + 'A'
【解决方案3】:

目标是纯十六进制的,还是函数可以参数化。如果它被限制为十六进制,为什么不利用一个事实,即一个十六进制数字正好编码四位?

这就是我的做法:

#include <stdlib.h>

#include <limits.h> /* implementation's CHAR_BIT */

#define INT_HEXSTRING_LENGTH (sizeof(int)*CHAR_BIT/4)
/* We define this helper array in case we run on an architecture
   with some crude, discontinous charset -- THEY EXIST! */
static char const HEXDIGITS[0x10] = 
    {'0', '1', '2', '3', '4', '5', '6', '7',
     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
void int_to_hexstring(int value, char result[INT_HEXSTRING_LENGTH+1])
{
    int i;
    result[INT_HEXSTRING_LENGTH] = '\0';

    for(i=INT_HEXSTRING_LENGTH-1; value; i--, value >>= 4) {
        int d  = value & 0xf;
        result[i] = HEXDIGITS[d];
    }

    for(;i>=0;i--){ result[i] = '0'; }
}
int main(int argc, char *argv[])
{
    char buf[INT_HEXSTRING_LENGTH+1];

    if(argc < 2)
        return -1;

    int_to_hexstring(atoi(argv[1]), buf);
    puts(buf);
    putchar('\n');

    return 0;
}

【讨论】:

  • 优雅得体。
【解决方案4】:

我做了一个库来进行十六进制/十进制转换,而不使用stdio.h。使用非常简单:

char* dechex (int dec);

这将使用calloc()来返回一个指向十六进制字符串的指针,这样使用的内存量得到了优化,所以不要忘记使用free()

这里是github上的链接:https://github.com/kevmuret/libhex/

【讨论】:

    【解决方案5】:
    #include<stdio.h>
    
    char* inttohex(int);
    main()
    {
        int i;
        char *c;
        printf("Enter the no.\n");
        scanf("%d",&i);
        c=inttohex(i);
        printf("c=%s",c);
    }
    
    char* inttohex(int i)
    {
        int l1,l2,j=0,n;
        static char a[100],t;
    
        while(i!=0)
        {
        l1=i%16;
        if(l1>10)
        {
            a[j]=l1-10+'A';
        }
    
        else
            sprintf(a+j,"%d",l1);
    
        i=i/16;
        j++;
        }
        n=strlen(a);
        for(i=0;i<n/2;i++)
        {
            t=a[i];
            a[i]=a[n-i-1];
            a[n-i-1]=t;
        }
    
        //printf("string:%s",a);
        return a;
        //
    }
    

    【讨论】:

      【解决方案6】:

      作为其他好答案的补充......

      如果这些十六进制或十进制字符串表示的数字很大(例如数百位),它们将不适合 long long(或您的 C 实现提供的任何最大整数类型)。然后你需要bignums。我建议不要编写自己的实现代码(制作一个高效的实现很棘手),而是使用现有的,例如 GMPlib

      【讨论】:

        猜你喜欢
        • 2018-01-22
        • 2018-01-31
        • 2012-02-03
        • 2015-02-06
        • 2019-07-27
        • 2015-09-21
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        相关资源
        最近更新 更多