Czy ta zamiana float na binarnie jest zrobiona poprawnie ?

0
#include <stdio.h>
#include <stdlib.h>
#define ROZMIAR 8*sizeof(int)
#define MASKA 1
union sex{
	float a;
	int b;
}u;

int main(int argc,char *argv[]){	
	int i,b;
	char tab[ROZMIAR];
	u.a=atof(argv[1]);
	for(i=ROZMIAR-1;i>=0;i--){
	tab[i]=u.b&MASKA;
	u.b=u.b>>1;}
	for(i=0;i<=ROZMIAR-1;i++) printf("%d",tab[i]);
	
	return 0;
} 
0

Praktycznie tak, większość kompilatorów przetworzy ten kod zgodnie z oczekiwaniami. Teoretycznie nie, zgodnie ze standardem dostęp do innej zmiennej w unii niż została wpisana jest undefined.

0

Podobno coś w stylu

int b=*(int*)&float;

jest undefined behavior w c

0

W zasadzie obie te rzeczy są undefined. :-D Obie w praktyce powinny zadziałać, ale wcale nie muszą. Co do tej drugiej, czyli strict aliasing rule, to można użyć odpowiedniej flagi kompilatora albo innej pragmy czy pragmopodobnej rzeczy, żeby zapewnić prawidłowe działanie. (Np. __attribute__((__may_alias__)) w GCC)

0

To jak mozna to zrobic inaczej ? Po prostu dzieląc ?

0

Jeszcze dodam, że rozwiązanie z uniami jest zdecydowanie lepsze, niż z rzutowaniem wskaźników. Takie zastosowanie unii jest dość popularnym idiomem, mimo bycia undefined i jest powszechnie wspierane. Z kolei rzutowanie wskaźników jest niezgodne z strict aliasing rule, co powoduje albo bugi w zoptymalizowanym kodzie (gdzie je trudno wykryć), albo musisz zrezygnować z dość skutecznej optymalizacji przez ustawianie flag w kompilatorze.

Jeżeli chcesz być w 100 % pewny do zachowania jakiegokolwiek kompilatora zgodnego ze standardem, to rzutuj wskaźnik do tego floata na char*, wtedy masz na pewno dostęp do aktualnej wartości w tym miejscu w pamięci. Następnie po prostu obrób 4 (czy sizeof(float)) chary od tego wskaźnika.

0

W zasadzie obie te rzeczy są undefined. :-D Obie w praktyce powinny zadziałać, ale wcale nie muszą
pierwsza na chłopski rozum powinna być „implementation dependent” a nie „undefined”, ale nie chce mi się teraz szukać jak jest w standardzie.

strict aliasing na pewno jest undefined.

0

wypisujesz bity od najmłodszego do najstarszego, czyli w odwrotnej kolejności niż przyjęło się to robić.

0
  1. Nie wiem skąd się wziął wzór na ROZMIAR (??)
  2. w unii powinien być unsigned int
  3. czy na pewno to jest dopuszczalne żeby robić auto-magiczne printf %d z parametrem char? Innymi słowy czy kompilator rozpozna że ma odłożyć na stosie int bo miał %d w łańcuchu?
1
Endrju napisał(a)

Jest undefined, sprawdzałem w C11. (6.2.6.1 punkt 7)

zobaczmy:

N1570 napisał(a)

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

ja to rozumiem, że unspecified są bajty, które wystają poza zapisanego członka unii, np.

union {
  char c;
  int i;
}

zapisanie jednego bajta do c powoduje unieważnienie (w sensie unspecified) trzech pozostałych bajtów inta (zakładając 32 bity), ale nie pierwszego z nich, bo tam trafia c.

0

Nie do końca. Jak zapiszesz float a odczytasz int to nie wiadomo co dostaniesz. Kompilator nie musi o to w ogóle dbać. Nie mówiłem o tym, czy to zadziała czy nie, nie musi. Kompilator może to w jakiś sposób zoptymalizować lub inaczej spowodować, że nie dostaniesz wcale binarnej reprezentacji float.

Kto powiedział, że to trafi do 1 bajta? A może gdzieś całkiem w środek, bo tak na tej architekturze jest lepiej. To, że zazwyczaj to działa nie zmienia faktu, że nie musi.

Całkowicie bezpiecznym sposobem jest użycie np. memcpy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1