C отпечатване на char масив като 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, число, което е много по-голямо от това, което може да съхрани променлива float; изходът трябва да бъде, в научна нотация, 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 PC ще даде същия резултат.   -  person Cristi    schedule 18.08.2012
comment
ако бях на твое място, щях да запиша този масив във файл с помощта на fwrite, след което да го прочета като float с помощта на fread (четене на float). Това може да ви даде намек за проблема с endianness   -  person Seçkin Savaşçı    schedule 18.08.2012


Отговори (2)


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

Най-голямата крайна стойност, която IEEE float с единична точност може да съхрани, е 3,4028234 × 10^38, така че 283135145630880207619489792,000000, което е приблизително 2,8313514 × 10^26, определено е в диапазона.

Ако приемем, че вашите знаци иначе са правилни, предположението на колене би било, че сте сбъркали endianity.

РЕДАКТИРАНЕ: 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, което е, което искате.

В Little Endian:

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
Ами прецизността? Мислех, че float мантисата може да съхранява само 7 цифри. - person Cristi; 18.08.2012
comment
Различните процесори определено биха дали различни резултати. Когато четат 32-битова стойност, някои смятат, че най-значимият байт е първият, но някои го смятат за последен. Мисля, че току-що сте използвали английския ред на четене (т.е. отляво надясно) на CPU с малък ред (т.е. такъв, който чете отдясно наляво). - person Tommy; 18.08.2012
comment
Да, така е, това е Linux x86-64, Благодаря ви много! - person Cristi; 18.08.2012

Това, което всъщност виждате, е {'k' 'j' '4' '3'}

person user12410214    schedule 30.01.2013