在C语言中将十六进制转换为浮点数、浮点数转换为十六进制

3
我正在尝试编写一个算法,将十六进制数转换为浮点数或将浮点数转换为十六进制数。这是一个作业的一部分,程序应该接收以“0x”开头的8位十六进制数或浮点数,并使用计算机的“内置IEEE 754功能”将数字转换为十六进制或浮点数。代码应该用C语言编写。
我的方法如下。将用户输入存储为字符串。将输入字符数组传递给一个方法,检查它是否为十六进制数,通过检查数组的前两个位置,这些位置应为0和X(假定所有十六进制数都是以此方式传递的)。如果是这种情况,则检查十六进制数的格式是否正确,即不要有过多的数字或数字超出了0-15范围(还考虑了ABCDEF约定)。
因此,我的问题是,我不知道如何将此数组转换回可以用来转换为浮点数的数字。我考虑使用sscanf将其转换回浮点数,但我不太熟悉C,也没有在网上找到任何好的资料。
能否有人指点我正确的方向?我还考虑同时将用户输入存储为字符串和数字,但我不确定是否可能。
这里是两个形式检查函数和不完整的主方法:
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 lib。

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); - Floris
@Floris 在打印 double 时,l 是可选的,不是必需的。 - chux - Reinstate Monica
4个回答

16

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

#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

如预期所料。有关相关主题的更多详细信息,请参见我对你其他问题的答案

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


有点难猜...你能展示一下重现问题的关键代码吗?<stdint.h>只是确保uint32_t类型存在且长度为四个字节 - 你可以查看sizeof(int) == 4,如果是这样,你可以直接使用int而不需要stdint.h。否则,请使用long int代替。但请展示一些代码。如有必要,请编辑你的问题。 - Floris
感谢您添加代码,问题现在非常简单。您正在使用double(这是一个8字节的数字),而不是float-因此您没有查看整个数字。实际上,你很幸运这并没有崩溃...如果您只需在代码中将double替换为float,一切都会好起来(假设sizeof(int)==4)。我包含的头文件(不是库!)仅保证类型的大小,但是如果您知道您的编译器,那么很容易弄清楚int有多大,然后您就不需要<stdint.h>-也不必使用uint32_t - Floris
1
不过 int 仍然只有四个 字节(32 )长(尽管它可以表示像 12345678 这样的数字)。而 double 则是八个 字节 长。建议使用 float - Floris
检查sizeof(int)sizeof(float) - 两个都应该是4。 - Floris
1
很抱歉要说,虽然这是一个在过去还可以的技巧,而且也可能仍然有效,但它违反了"strict aliasing"的规则,因此不能再推荐使用了。 - Steve Summit
显示剩余3条评论

2

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

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

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

现在将该技术应用到十六进制。下面是一个代码片段,可以处理单个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" - chux - Reinstate Monica

0
你需要使用乘法或位运算。在完成所描述的边界/十六进制检查后,执行类似以下代码的操作:
float x = 0;
for(i=0;i<8;i++)
{
 x += getDecimalValue(inputArray[i+2]) << (4*(7-i))
}

以下是未经测试的代码,您需要将字符转换为十进制值(A=10,B=11等)。该位运算相当于将十六进制字符的十进制等价值乘以2^numberOfBits。此答案假定左侧的十六进制为最高有效位(大端序),对于小端序请反转操作。


1
减去48会将'0'(0x30或48)变成0;如果>9,则减去7将'A'(65==48+10+7)变成10 - luser droog

0
如果输入的形式为:“0x......”则
float f;
long l;

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

printf("%f", f);

valter


1
不行。这会将十六进制数的转换为float。OP想要使用原始位。例如,他们希望0x40480000转换为3.125,而不是1078460416.0 - Steve Summit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接