【问题标题】:Convert a hexadecimal to a float and viceversa in C在 C 中将十六进制转换为浮点数,反之亦然
【发布时间】:2014-01-24 02:07:21
【问题描述】:

我正在尝试编写一个算法来将十六进制数转换为浮点数,反之亦然。这是作业的一部分,程序应该接收以“0x”开头的 8 位十六进制数或浮点数,并使用计算机的“内置 IEEE 754 功能”将数字转换为十六进制或浮点数。代码应该在 C 中。

我的方法如下。将用户的输入存储为字符串。将输入 char 数组传递给一个方法,该方法通过检查数组的前两个位置(应该是 0 和 X)来检查它是否是十六进制数(假设所有十六进制数都以这种方式传递)。如果是这种情况,那么我会检查十六进制的格式是否正确,即 0-15 范围之外的数字或数字不要太多(也考虑到 ABCDEF 约定)。

所以,我的问题是,我不知道如何将这个数组转换回我可以用来转换为浮点数的数字。我考虑过使用 sscanf 将其转回浮点数,但我对 C 的了解不够,也没有在网上找到任何好的资源

有人能指出我正确的方向吗?我还考虑过将用户输入同时存储为字符串和数字,但我不确定这是否可行。

这里有两个表单检查函数和不完整的main方法:

int is_hex(char arr[])
{
    if (arr[0] == '0' && (arr[1] == 'x' || arr[1] == 'X')) {
        return 1;
    }
    return 0;
}

int check_if_good(char arr[])
{
    if (is_hex(arr)) {
        int len = strlen(arr);
        for (int i = 2; i < len; i++) {
            if ((arr[i] > 'f' && arr[i] <= 'z') || (arr[i] > 'F' && arr[i] <= 'Z')) {
                return 0;
            }
        }
    }

    return 1;
}

int main(int argc, const char * argv[])
{
    float x;
    char input[30];
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

如果有人也能告诉我'%x' 的基本含义,我将不胜感激。据我了解,它可以让我以十六进制形式收集数字,但我可以将它们存储在整数和浮点数中吗?非常感谢您的帮助。

--编辑:floris 的额外代码。我试图在不使用任何额外库的情况下解决这个问题,所以你不能使用 stdint 库。

char input[30];
scanf("%s", input);
if(check_if_good(input)){  //Ignore this if-statement.
    printf("Input is in hex form");
}
int num = convert_hex_string(input); // this function works perfectly. It return the int form of the hex.
double f = *((double*)&num);
printf("%f\n", f);

【问题讨论】:

  • "%x" 表示您写入数字的十六进制值。例如unsigned char i = 10; printf("%x", i); 将给出a
  • 请注意,当fdouble 时,您需要执行printf("%lf", f);...

标签: c arrays floating-point hex


【解决方案1】:

如果你真的想知道一个特定的十六进制字符串代表什么浮点数,你可以将字符串转换为整数,然后查看地址假装它包含浮点数。以下是它的工作原理:

#include <stdint.h>
#include <stdio.h>

int main(void) {
  char myString[]="0x3f9d70a4";
  uint32_t num;
  float f;
  sscanf(myString, "%x", &num);  // assuming you checked input
  f = *((float*)&num);
  printf("the hexadecimal 0x%08x becomes %.3f as a float\n", num, f);
}

这会作为输出产生

the hexadecimal 0x3f9d70a4 becomes 1.230 as a float

正如预期的那样。详情请见my answer to your other question about a related topic

还应该很容易看出如何反向执行上述操作 - 从浮点数开始,然后获取十六进制表示。

【讨论】:

  • 嘿弗洛里斯!我正在尝试在没有 库的情况下实现您的代码。一切正常,我能够通过遍历内容并进行一堆乘法来将十六进制字符串转换为其整数值。但是,现在当我尝试打印它的浮点表示时,我总是得到 0.0000,你知道可能出了什么问题吗?谢谢!
  • 有点难猜...你能给出重现你的问题的关键行吗? &lt;stdint.h&gt; 只是确保 uint32_t 类型存在并且长度为四个字节 - 您可以查看 sizeof(int) == 4 在这种情况下是否可以使用 int 而您不需要 stdint.h。否则,请改用long int。但是显示一些代码。如果需要,请编辑您的问题。
  • 感谢添加代码;现在的问题真的很简单。您正在使用 double(这是一个 8 字节的数字)而不是 float - 所以您不是在查看整数。事实上,你很幸运,这不只是崩溃......如果你只是在你的代码中用float 替换double,一切都会好起来的(假设sizeof(int)==4)。我包含的头文件(不是库!)只是保证类型的大小,但是如果你知道你的编译器很容易弄清楚int 有多大,那么你就不需要&lt;stdint.h&gt; - 并且不必使用uint32_t
  • 考虑到我正在将十六进制转换为整数,我的整数不会由 32 位组成,因为十六进制是这个大小,然后通过将其转换为浮点数将其转换为 IEEE 754 ?那么,如果 int 的大小远大于 4,应该怎么做呢?这种现场帮助是发生在我身上的最好的事情。谢谢。
  • 不,int 仍然只有四个 字节(32 )长(尽管它可能表示像 12345678 这样的数字)。 double 有八个 字节 长。使用float
【解决方案2】:

如果你被允许使用库函数,试试 atoi(arr) 或 sscanf(arr+2, "%x", &num)

如果您想手动解析字符串,请考虑如何转换十进制数。例如,将“2987”转换为整数...

int n = 0;
n += 1000 * 2;
n += 100  * 9;
n += 10   * 8;
n += 1    * 7;

现在将该技术应用于十六进制。这是一个代码 sn-p 来处理单个 ascii 字符:

int char_to_int(char c) {
   if (c >= '0' && c <= '9') return c - '0';
   if (c >= 'A' && c <= 'F') return c - 'A' + 10;
   return 0; /* oops, something else... */
}

【讨论】:

  • arr+2 可以简单地为arr"%x" 将使用 "0x"
【解决方案3】:

如果input的格式为:“0x......”那么

float f;
long l;

l = strtol(input, (char**)NULL, 16);
f = (float)l;

printf("%f", f);

变态

【讨论】:

    【解决方案4】:

    要将一串十六进制或浮点字符转换为float

    float StringToFloat(const char *s) {
      // OP's is_hex()
      if ((*s == '0') && ((*s == 'X') || (*s == 'x'))) {
        unsigned long ul = strtoul(d, NULL, 16);
        return  (float) ul;
      }
      double d = atof(s, NULL);
      return (float) d;
    }
    // Error handling omitted.
    

    要将float 转换为十六进制字符串:

    // return 1 on error
    int StringToFloat(char *dest, float x) {
      float y = roundf(x);
      if ((x != y) || (y >= 4294967296.0f) || (y < 0.0f)) return 1;
      sprintf(dest, "0x%lx", (unsigned long) y);
      return 0;
    }
    

    在没有库函数的情况下将十六进制字符串转换为floatunsigned long
    假设ASCII)。

    // Substitute unsigned long for float as desired.
    // Error return handing is then different.
    float HexStringToFloat(const char *s) {
      if ((*s != '0') || ((*s != 'X') && (*s != 'x'))) {
        return NAN;  // Not-a-number macro from math.h
      }
      float x = 0;
      int ch;
      while ((ch = *s++) != '\0') {
        static const char HexDigit[] = "0123456789ABCDEFabcdef";
        int i = 0;
        while (1) {
          if (HexDigit[i] == '\0') return NAN;
          if (HexDigit[i] == ch) break;
          i++; 
        }
        if (i >= 16) i -= 6;
        x *= 16;
        x += i;
      }
      return x;
    }
    

    【讨论】:

      【解决方案5】:

      您需要使用乘法或位运算。完成您描述的边界/十六进制检查后,执行以下操作:

      float x = 0;
      for(i=0;i<8;i++)
      {
       x += getDecimalValue(inputArray[i+2]) << (4*(7-i))
      }
      

      这是未经测试的代码,您需要将字符转换为十进制值(A=10,B=11 等)。该按位运算与将十六进制字符的十进制等效值乘以 2^numberOfBits 相同。这个答案是假设最左边的十六进制是最重要的(大端),反转小端的操作。

      【讨论】:

      • 减去 48 将 '0'(0x30 或 48) 变为 0;如果是&gt;9,则减7,将'A'(65==48+10+7) 变为10
      猜你喜欢
      • 1970-01-01
      • 2012-09-18
      • 2011-03-23
      • 2021-07-17
      • 1970-01-01
      • 2010-09-17
      • 2014-03-01
      • 1970-01-01
      • 2018-09-22
      相关资源
      最近更新 更多