C печатает массив символов как float

Я пытаюсь напечатать массив символов из 4 элементов в виде числа с плавающей запятой. Компилятор (gcc) не позволяет мне писать z.s={'3','4','j','k'}; в функции main(), почему?

#include <stdio.h>

union n{
    char s[4];
    float x;
};
typedef union n N;

int main(void)
{
    N z;
    z.s[0]='3';
    z.s[1]='4';
    z.s[2]='j';
    z.s[3]='k';
    printf("f=%f\n",z.x);
    return 0;
}

Вывод приведенной выше программы: f=283135145630880207619489792.000000 , число, которое намного больше, чем может хранить переменная с плавающей запятой; вывод должен быть в экспоненциальном представлении 4.1977085E-8. Так что же не так?


person Cristi    schedule 18.08.2012    source источник
comment
Возможно, Endianness?   -  person Sebastian Paaske Tørholm    schedule 18.08.2012
comment
Вы думали о больших/маленьких индийских проблемах?   -  person Picarus    schedule 18.08.2012
comment
Я предполагаю, что любой компьютер с архитектурой x86 или x86-64 даст тот же результат.   -  person Cristi    schedule 18.08.2012
comment
на вашем месте я бы записал этот массив в файл, используя fwrite, а затем прочитал бы его как число с плавающей запятой, используя fread (чтение числа с плавающей запятой). Это может дать вам подсказку о проблеме порядка байтов   -  person Seçkin Savaşçı    schedule 18.08.2012


Ответы (2)


z.s={'3','4','j','k'}; назначит один массив другому. C не позволяет этого, хотя вы можете объявить второй и memcpy для первого.

Наибольшее конечное значение, которое может хранить число с плавающей запятой одинарной точности IEEE, составляет 3,4028234 × 10^38, поэтому 283135145630880207619489792,000000, что приблизительно равно 2,8313514 × 10^26, определенно находится в диапазоне.

Предполагая, что ваши символы в остальном верны, рефлекторная догадка будет заключаться в том, что вы ошиблись с порядком байтов.

РЕДАКТИРОВАТЬ: 34jk, если брать слева направо, как на машине с прямым порядком байтов:

0x33 0x34 0x6a 0x6b
= 0011 0011, 0011 0100, 0110 1010, 0110 1011

So:

sign = 0
exponent = 011 0011 0 = 102 (dec), or -25 allowing for offset encoding
mantissa = [1] 011 0100 0110 1010 0110 1011 = 11823723 / (2^23)

Таким образом, значение будет примерно 4,2 × 10 ^ -8, что вам и нужно.

С прямым порядком байтов:

0x6b 0x6a 0x34 0x33 
= 0110 1011, 0110 1010, 0011 0100, 0011 0011

sign = 0
exponent = 110 1011 0 = 214 (dec) => 87
mantissa = [1]110 1010 0011 0100 0011 0011 = 15348787 / (2^23)

Таким образом, значение будет около 2,8 * 10 ^ 26, что и выводит ваша программа. Это безопасный вывод, что вы находитесь на машине с прямым порядком байтов.

Резюме: порядок байтов на разных машинах разный. Вы хотите использовать свои байты наоборот — попробуйте kj43.

person Tommy    schedule 18.08.2012
comment
Значит, другой компилятор может дать другой результат? - person Cristi; 18.08.2012
comment
Как насчет точности? Я думал, что мантисса с плавающей запятой может хранить только 7 цифр. - person Cristi; 18.08.2012
comment
Различные процессоры определенно дадут разные результаты. При чтении 32-битного значения некоторые считают самый старший байт первым, а некоторые — последним. Я думаю, вы только что использовали английский порядок чтения (т. е. слева направо) на процессоре с прямым порядком байтов (т. е. тот, который читает справа налево). - person Tommy; 18.08.2012
comment
Да, это линукс x86-64, спасибо большое! - person Cristi; 18.08.2012

На самом деле вы видите {'k' 'j' '4' '3'}

person user12410214    schedule 30.01.2013