Czy istnieje jednowierszowa definicja makra określająca endianness maszyny? Używam następującego kodu, ale konwersja go na makro byłaby zbyt długa.
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char *test_endian = (unsigned char*)&test_var;
return (test_endian[0] == 0);
}
c
architecture
macros
endianness
manav mn
źródło
źródło
0
zamiastNULL
w swoim ostatnim teście i zmienić jeden ztest_endian
obiektów na inny :-).#if
dyrektywy.Odpowiedzi:
Kod obsługujący dowolne rozkazy bajtów, gotowy do umieszczenia w pliku o nazwie
order32.h
:Sprawdziłbyś systemy little endian za pośrednictwem
źródło
char
? Lepsze użycieuint8_t
i niepowodzenie, jeśli ten typ nie jest dostępny (co można sprawdzić za pomocą#if UINT8_MAX
). Zauważ, żeCHAR_BIT
jest niezależny oduint8_t
.O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 */
Jeśli masz kompilator obsługujący literały złożone C99:
lub:
Generalnie jednak powinieneś spróbować napisać kod, który nie zależy od endianness platformy hosta.
Przykład implementacji niezależnej od endianności hosta
ntohl()
:źródło
ntohl
w sposób, który nie zależy od endianness platformy hosta.Nie ma standardu, ale w wielu systemach, w tym
<endian.h>
, podaje kilka definicji, których należy szukać.źródło
#if __BYTE_ORDER == __LITTLE_ENDIAN
i#elif __BYTE_ORDER == __BIG_ENDIAN
. I generuj w#error
inny sposób.<endian.h>
nie jest dostępny w systemie Windowsendian.h
chyba że zdefiniowano__APPLE__
lub_WIN32
.#if BYTE_ORDER == LITTLE_ENDIAN
(lubBIG_ENDIAN
) bez podkreślenia przed nazwami._BYTE_ORDER
dotyczy tylko nagłówków systemowych.__BYTE_ORDER
nie istnieje.Aby wykryć endianness w czasie wykonywania, musisz być w stanie odwołać się do pamięci. Jeśli trzymasz się standardowego C, deklarowanie zmiennej w pamięci wymaga instrukcji, ale zwrócenie wartości wymaga wyrażenia. Nie wiem, jak to zrobić w pojedynczym makrze - dlatego gcc ma rozszerzenia :-)
Jeśli chcesz mieć plik .h, możesz zdefiniować
a następnie możesz używać
ENDIANNESS
makra, jak chcesz.źródło
Jeśli chcesz polegać tylko na preprocesorze, musisz znaleźć listę predefiniowanych symboli. Arytmetyka preprocesora nie ma pojęcia adresowania.
GCC na Macu definiuje
__LITTLE_ENDIAN__
lub__BIG_ENDIAN__
Następnie możesz dodać więcej dyrektyw warunkowych preprocesora na podstawie wykrywania platformy, np
#ifdef _WIN32
.źródło
#define __BIG_ENDIAN__ 1
i#define _BIG_ENDIAN 1
.#define __LITTLE_ENDIAN__ 1
. To makro wydaje się być funkcją clang, a nie funkcją gcc.gcc
Komenda w niektórych komputerach Mac nie jest gcc, to dzyń.Uważam, że o to właśnie proszono. Przetestowałem to tylko na małej maszynie endian pod msvc. Ktoś proszę potwierdzić na maszynie Big Endian.
Na marginesie (specyficzne dla kompilatora), z agresywnym kompilatorem możesz użyć optymalizacji "eliminacji martwego kodu", aby osiągnąć taki sam efekt jak czas kompilacji,
#if
taki jak ten:Powyższe opiera się na fakcie, że kompilator rozpoznaje wartości stałe w czasie kompilacji, całkowicie usuwa kod w
if (false) { ... }
środku i zastępuje kod jakif (true) { foo(); }
wfoo();
przypadku najgorszego przypadku: kompilator nie przeprowadza optymalizacji, nadal otrzymujesz poprawny kod, ale nieco wolniej.źródło
'ABCD'
?clang -Wpedantic -Werror -Wall -ansi foo.c
i spowoduje to błąd. (Szczęk, a to w szczególności:-Wfour-char-constants -Werror
)Jeśli szukasz testu czasu kompilacji i używasz gcc, możesz wykonać:
Więcej informacji znajdziesz w dokumentacji gcc .
źródło
__BYTE_ORDER__
jest dostępny od GCC 4.6Państwo może w rzeczywistości dostęp do pamięci tymczasowej obiektu za pomocą dosłownym związek (C99):
Które GCC oceni w czasie kompilacji.
źródło
#if __STDC_VERSION__ >= 199901L
.„Biblioteka sieci C” oferuje funkcje do obsługi endii. Mianowicie htons (), htonl (), ntohs () i ntohl () ... gdzie n to "sieć" (tj. Big-endian), a h to "host" (tj. Endian'ness maszyny, na której działa kod).
Te pozorne „funkcje” są (powszechnie) definiowane jako makra [patrz <netinet / in.h>], więc ich używanie nie wiąże się z żadnymi kosztami wykonania.
Poniższe makra używają tych „funkcji” do oceny endian „ness ”.
Dodatkowo:
Jedynym przypadkiem, w którym kiedykolwiek muszę poznać endian'ness systemu, jest zapisanie zmiennej [do pliku / innego], która może być wczytywana przez inny system o nieznanym endian'ness (dla kompatybilności między platformami ) ... W takich przypadkach możesz preferować bezpośrednie użycie funkcji endian:
źródło
Użyj funkcji wbudowanej zamiast makra. Poza tym trzeba coś zapisać w pamięci, co jest niezbyt przyjemnym efektem ubocznym makra.
Możesz przekonwertować je na krótkie makro za pomocą zmiennej statycznej lub globalnej, na przykład:
źródło
s_endianess
na początku nie jest ustawiona wartość 1?Chociaż nie ma przenośnego #define lub czegoś, na czym można by polegać, platformy zapewniają standardowe funkcje do konwersji do iz endianu hosta.
Ogólnie rzecz biorąc, przechowujesz - na dysk lub w sieci - używając „endian sieci”, czyli BIG endian, oraz lokalnych obliczeń przy użyciu hosta endian (który na x86 to LITTLE endian). Używasz
htons()
intohs()
i znajomych do konwersji między nimi.źródło
źródło
Nie zapominaj, że endianness to nie wszystko - rozmiar
char
może nie wynosić 8 bitów (np. DSP), negacja dopełniacza do dwóch nie jest gwarantowana (np. Cray), może być wymagane ścisłe wyrównanie (np. SPARC, również ARM sprężyny w środku -endian gdy niewyrównane) itp., itp.Lepszym pomysłem może być wybranie określonej architektury procesora zamiast tego .
Na przykład:
Zwróć uwagę, że to rozwiązanie również nie jest niestety ultraprzenośne, ponieważ zależy od definicji specyficznych dla kompilatora (nie ma standardu, ale tutaj jest ładna kompilacja takich definicji).
źródło
Spróbuj tego:
źródło
Proszę zwrócić uwagę, że większość odpowiedzi tutaj nie jest przenośna, ponieważ dzisiejsze kompilatory ocenią te odpowiedzi w czasie kompilacji (zależy od optymalizacji) i zwrócą określoną wartość na podstawie określonej endianness, podczas gdy faktyczna endianness maszyny może się różnić. Wartości, na których testowana jest endianność, nigdy nie dotrą do pamięci systemowej, dlatego rzeczywisty wykonywany kod zwróci ten sam wynik, niezależnie od rzeczywistej endianności.
Na przykład w ARM Cortex-M3 zaimplementowana endianness będzie odzwierciedlać bit stanu AIRCR.ENDIANNESS i kompilator nie może znać tej wartości w czasie kompilacji.
Dane wyjściowe kompilacji niektórych z sugerowanych tutaj odpowiedzi:
https://godbolt.org/z/GJGNE2 w tym celu odpowiedzi,
https://godbolt.org/z/Yv-pyJ w tym celu odpowiedzi i tak dalej.
Aby go rozwiązać, musisz użyć
volatile
kwalifikatora.Yogeesh H T
„s odpowiedź jest najbliższy dzisiejszego użytkowania prawdziwym życiu, ale ponieważChristoph
sugeruje bardziej kompleksowe rozwiązania, niewielkie poprawki do jego odpowiedź może sprawić, że odpowiedź pełna, wystarczy dodaćvolatile
do deklaracji związków:static const volatile union
.Zapewniłoby to przechowywanie i czytanie z pamięci, co jest potrzebne do określenia endianizmu.
źródło
Jeśli zrzucisz preprocesor #defines
Zwykle możesz znaleźć rzeczy, które ci pomogą. Z logiką czasu kompilacji.
Jednak różne kompilatory mogą mieć różne definicje.
źródło
Moja odpowiedź nie jest tak zadawana, ale naprawdę łatwo jest sprawdzić, czy Twój system to little endian czy big endian?
Kod:
źródło
C Kod do sprawdzania, czy system jest typu little-endian czy big-indian.
źródło
Makro do znalezienia endian
lub
źródło