2011-12-15 16 views
10

Proszę rozważyć następujący kod:unikać reprezentacja pułapka z memcpy

float float_value = x; // x is any valid float value 
int int_value = 0; 
size_t size = sizeof(int) < sizeof(float) ? sizeof(int) : sizeof(float); 
memcpy(&int_value, &float_value, size); 

O ile wiem, może to doprowadzić do reprezentacji pułapkę. Moje pytania:

  1. Czy to prawda?
  2. Jeśli nie, dlaczego?
  3. Jeśli nie, czy istnieje inny sposób uniknięcia możliwej reprezentacji pułapki?
+0

To w zasadzie wygląda na złe nieokreślone zachowanie. Int i float mogą mieć różne rozmiary. Co tak naprawdę próbujesz osiągnąć? – EvilTeach

+2

Czy próbujesz zobaczyć binarną reprezentację float? memcpy() to rozwiązanie dla bomb jądrowych, w którym mógłby działać prosty młotek z przypisem z typografią. –

+1

Można użyć unsigned int i uniknąć problemów. – TJD

Odpowiedz

10

przyznany na sposób, który nie przyniesie żadnej reprezentacji pułapka

unsigned char obj[sizeof float]; 
memcpy(obj, &float_value, sizeof float); 

Następnie można użyć bajtów reprezentacji obiektu budować pożądany int.

Ale używanie liczb całkowitych o stałej szerokości, o czym wspomniał Stephen Canon jest lepsze - chyba że masz dziwny rozmiar float.

+0

C99: http://blackshell.com/~msmud/cstd.html#6.2.6.1 – u0b34a0f6ae

+0

Właściwie, dla konkretnego celu mieszania, podoba mi się to rozwiązanie. –

+0

@ kaizer.se Dzięki za link do standardu. –

2

Tak, może to skutkować reprezentacją pułapki. Jeśli chodzi o sposób, aby tego uniknąć:

  • twierdzą, że sizeof(int32_t) == sizeof(float)
  • Zastosowanie int32_t zamiast int.

Liczby całkowite o stałej szerokości nie mogą przyjmować odwzorowań pułapek. W szczególności standard wymaga, aby nie zawierały bitów dopełniających i nie można uzyskać reprezentacji pułapki bez dopełnienia.

+0

jesteś tego pewien? i chociaż tylko * unsigned char * nigdy nie pułapki. czy mógłbyś zacytować C99? Dziękuję za odpowiedź! – Johannes

+0

@Johannes: §7.1.1.1.1 "Nazwa typu intN_t oznacza podpisany typ całkowity o szerokości N, brak bitów dopełnienia i reprezentację uzupełnienia dwójki." Ponieważ nie ma bitów dopełniających, wszystkie N bitów są * wartościami * bitowymi, a zatem każda kombinacja bitów ma wartość zdefiniowaną przez standard i nie może być reprezentacją pułapki. –

+0

@Stephen, możesz mieć reprezentację pułapki bez dopełnienia, a mianowicie ograniczenia, które cytujesz, pozostawiają dwie możliwe wartości dla 'INTXX_MIN'. Ale standard zamyka tę lukę, ustalając, co ma mieć wartość dodatkowo. W kopii mam nawet wygląda, że ​​została dodana później z jedną z aktualizacji. –

3

Nie potrzebujesz memcpy, jeśli chcesz tylko sprawdzić wartości tam. Najprościej jest po prostu rzucić

unsigned char const* p = &float_object; 

wskaźnika obsady do wszystkich typów char jest zawsze gwarantowane dać coś ważnego, z którym można wykonywać proste działania arytmetyczne. Jesteś bezpieczny tak długo, jak robisz dereferencje w granicach podanych przez sizeof float_object.

Jeśli chcesz traktować tę liczbę jako najbezpieczniejszą, wybierz liczbę całkowitą bez znaku o stałej szerokości, najprawdopodobniej uint32_t. Jeśli wiesz, że wymagania dotyczące szerokości są spełnione, to powinno dać ci wszystko, czego potrzebujesz.

Jak wspomniano, działa to tak długo, jak długo nie piszemy przez ten wskaźnik. Następnie reguły aliasingu dla wskaźników mogą później spowodować, że optymalizator ulegnie błędowi.