it-swarm.com.de

C Makrodefinition zur Bestimmung der Big-Endian- oder Little-Endian-Maschine?

Gibt es eine einzeilige Makrodefinition, um die Endianzeit der Maschine zu bestimmen Ich verwende den folgenden Code, aber das Konvertieren in Makro wäre zu lang.

unsigned char test_endian( void )
{
    int test_var = 1;
    unsigned char test_endian* = (unsigned char*)&test_var;

    return (test_endian[0] == NULL);
}
91
manav m-n

Code, der willkürliche Byteaufträge unterstützt und in einer Datei namens order32.h abgelegt werden kann

#ifndef ORDER32_H
#define ORDER32_H

#include <limits.h>
#include <stdint.h>

#if CHAR_BIT != 8
#error "unsupported char size"
#endif

enum
{
    O32_LITTLE_ENDIAN = 0x03020100ul,
    O32_BIG_ENDIAN = 0x00010203ul,
    O32_PDP_ENDIAN = 0x01000302ul,      /* DEC PDP-11 (aka ENDIAN_LITTLE_Word) */
    O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 (aka ENDIAN_BIG_Word) */
};

static const union { unsigned char bytes[4]; uint32_t value; } o32_Host_order =
    { { 0, 1, 2, 3 } };

#define O32_Host_ORDER (o32_Host_order.value)

#endif

Sie würden über Little-Endian-Systeme über prüfen

O32_Host_ORDER == O32_LITTLE_ENDIAN
90
Christoph

Wenn Sie einen Compiler haben, der C99-Verbundliterale unterstützt:

#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})

oder:

#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)

Im Allgemeinen sollten Sie jedoch versuchen, Code zu schreiben, der nicht von der Endianness der Hostplattform abhängt.


Beispiel für die Host-endianness-unabhängige Implementierung von ntohl():

uint32_t ntohl(uint32_t n)
{
    unsigned char *np = (unsigned char *)&n;

    return ((uint32_t)np[0] << 24) |
        ((uint32_t)np[1] << 16) |
        ((uint32_t)np[2] << 8) |
        (uint32_t)np[3];
}
41
caf

Es gibt keinen Standard, aber auf vielen Systemen, einschließlich <endian.h>, erhalten Sie einige Definitionen.

Um Endianness zur Laufzeit zu erkennen, müssen Sie auf den Speicher zugreifen können. Wenn Sie sich an Standard C halten, erfordert das Deklarieren einer Variablen im Speicher eine Anweisung, die Rückgabe eines Werts jedoch einen Ausdruck. Ich weiß nicht, wie man das in einem einzigen Makro macht - deshalb hat gcc Erweiterungen :-)

Wenn Sie eine .h-Datei haben möchten, können Sie definieren

static uint32_t endianness = 0xdeadbeef; 
enum endianness { BIG, LITTLE };

#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
                   : *(const char *)&endianness == 0xde ? BIG \
                   : assert(0))

und dann können Sie das ENDIANNESS-Makro wie gewünscht verwenden.

25
Norman Ramsey

Wenn Sie sich nur auf den Präprozessor verlassen wollen, müssen Sie die Liste der vordefinierten Symbole herausfinden. Präprozessor-Arithmetik hat kein Adressierungskonzept.

GCC auf dem Mac definiert __LITTLE_ENDIAN__ oder __BIG_ENDIAN__

$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1

Anschließend können Sie weitere bedingte Anweisungen für den Präprozessor hinzufügen, die auf der Plattformerkennung basieren, wie #ifdef _WIN32 usw.

19
Gregory Pakosz

Ich glaube, das war es, wonach ich gefragt wurde ... Ich habe dies nur auf einem kleinen Endian-Rechner unter msvc getestet. Jemand möchte dies auf einem Big-Endian-Rechner bestätigen. 

    #define LITTLE_ENDIAN 0x41424344UL 
    #define BIG_ENDIAN    0x44434241UL
    #define PDP_ENDIAN    0x42414443UL
    #define ENDIAN_ORDER  ('ABCD') 

    #if ENDIAN_ORDER==LITTLE_ENDIAN
        #error "machine is little endian"
    #Elif ENDIAN_ORDER==BIG_ENDIAN
        #error "machine is big endian"
    #Elif ENDIAN_ORDER==PDP_ENDIAN
        #error "jeez, machine is PDP!"
    #else
        #error "What kind of hardware is this?!"
    #endif

Als Randbemerkung (compilerspezifisch) können Sie mit einem aggressiven Compiler die Optimierung "Dead Code Elimination" verwenden, um die gleiche Wirkung wie eine Compilierzeit zu erzielen: #if wie folgt:

    unsigned yourOwnEndianSpecific_htonl(unsigned n)
    {
        static unsigned long signature= 0x01020304UL; 
        if (1 == (unsigned char&)signature) // big endian
            return n;
        if (2 == (unsigned char&)signature) // the PDP style
        {
            n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
            return n;
        }
        if (4 == (unsigned char&)signature) // little endian
        {
            n = (n << 16) | (n >> 16);
            n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
            return n;
        }
        // only weird machines get here
        return n; // ?
    }

Das Obige beruht auf der Tatsache, dass der Compiler die konstanten Werte zur Kompilierzeit erkennt, den Code in if (false) { ... } vollständig entfernt und Code wie if (true) { foo(); } durch foo(); ersetzt etwas langsamer.

14
ggpp23

Wenn Sie nach einem Kompilierzeit-Test suchen und gcc verwenden, können Sie Folgendes tun:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

Weitere Informationen finden Sie in der gcc-Dokumentation .

9
Jezz

Sie can greifen mit einem zusammengesetzten Literal (C99) auf den Speicher eines temporären Objekts zu:

#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})

Welche GCC wird zur Kompilierzeit auswerten.

7
u0b34a0f6ae

Die 'C-Netzwerkbibliothek' bietet Funktionen für den Umgang mit der Endianität. Htons (), htonl (), ntohs () und ntohl () ..., wobei n "Netzwerk" (d. H. Big-Endian) und h "Host" (dh die Endianität der Maschine ist, auf der das ausgeführt wird Code).

Diese scheinbaren "Funktionen" werden (im Allgemeinen) als Makros definiert [siehe <netinet/in.h>]], so dass kein Laufzeitaufwand für deren Verwendung entsteht.

Die folgenden Makros verwenden diese "Funktionen", um die Endianität zu bewerten.

#include <arpa/inet.h>
#define  IS_BIG_ENDIAN     (1 == htons(1))
#define  IS_LITTLE_ENDIAN  (!IS_BIG_ENDIAN)

In Ergänzung:

Ich muss die Endianität eines Systems nur dann kennenlernen, wenn ich eine Variable [in eine Datei/andere Datei] schreibe, die möglicherweise von einem anderen System mit unbekannter Endianität (zur plattformübergreifenden Kompatibilität) eingelesen wird ) ... In solchen Fällen können Sie die Endian-Funktionen direkt verwenden:

#include <arpa/inet.h>

#define JPEG_MAGIC  (('J'<<24) | ('F'<<16) | ('I'<<8) | 'F')

// Result will be in 'Host' byte-order
unsigned long  jpeg_magic = JPEG_MAGIC;

// Result will be in 'network' byte-order (IE. Big-Endian/Human-Readable)
unsigned long  jpeg_magic = htonl(JPEG_MAGIC);
7
BlueChip

Verwenden Sie eine Inline-Funktion anstelle eines Makros. Außerdem müssen Sie etwas im Speicher ablegen, das ein nicht so schöner Nebeneffekt eines Makros ist.

Sie können es mithilfe einer statischen oder globalen Variablen in ein kurzes Makro konvertieren.

static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
6
user231967

Zwar gibt es keine tragbare # Definition oder etwas, auf das Sie sich verlassen können, Plattformen bieten jedoch Standardfunktionen für die Konvertierung in und aus Ihrem 'Host'-Endian.

Im Allgemeinen führen Sie das Speichern von Datenträgern oder Netzwerkoperationen mit 'network endian' (BIG endian) und lokale Berechnungen mit Host endian durch (wobei x86 LITTLE endian ist). Sie verwenden htons() und ntohs() und Freunde, um zwischen den beiden zu konvertieren.

5
Will

Vergessen Sie nicht, dass Endianness nicht die ganze Geschichte ist - die Größe von char beträgt möglicherweise nicht 8 Bit (z. B. DSPs), eine Zweierkomplement-Negation ist nicht garantiert (z. B. Cray). Möglicherweise ist eine strikte Ausrichtung erforderlich (z. B. SPARC, auch ARM springt in middle-endian, wenn es nicht ausgerichtet ist) usw. usw.

Es ist möglicherweise eine bessere Idee, stattdessen eine bestimmte CPU-Architektur als Ziel festzulegen.

Zum Beispiel:

#if defined(__i386__) || defined(_M_IX86) || defined(_M_IX64)
  #define USE_LITTLE_ENDIAN_IMPL
#endif

void my_func()
{
#ifdef USE_LITTLE_ENDIAN_IMPL
  // Intel x86-optimized, LE implementation
#else
  // slow but safe implementation
#endif
}

Beachten Sie, dass diese Lösung leider auch nicht ultra-portabel ist, da sie von compilerspezifischen Definitionen abhängt (es gibt keinen Standard, aber hier ist eine nette Zusammenstellung solcher Definitionen).

3
rustyx
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
3
user1207334

Versuche dies:

#include<stdio.h>        
int x=1;
#define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian")
int main()
{

   TEST;
}
3
Prasoon Saurav

Bitte beachten Sie, dass die meisten Antworten hier nicht portierbar sind, da Compiler diese Antworten in der Kompilierzeit (abhängig von der Optimierung) auswerten und einen bestimmten Wert basierend auf einer bestimmten Endianness zurückgeben, während die tatsächliche Endianness der Maschine variieren kann. Die Werte, mit denen die Endiananness getestet wird, erreichen den Systemspeicher nicht. Daher wird der tatsächlich ausgeführte Code unabhängig von der tatsächlichen Endindianität dasselbe Ergebnis zurückgeben.

Für example wird in ARM Cortex-M3 die implementierte Endianness in einem Statusbit AIRCR dargestellt. ENDIANNESS und Compiler können diesen Wert nicht in der Kompilierzeit kennen.

Zusammenstellungsausgabe für einige der hier vorgeschlagenen Antworten:

https://godbolt.org/z/GJGNE2 für diese antwort,

https://godbolt.org/z/Yv-pyJ für diese antwort, und so weiter.

Um das Problem zu lösen, müssen Sie das Qualifikationsmerkmal volatile verwenden. Die Antwort von Yogeesh H T ist für die heutige Verwendung im realen Leben am nächsten, aber da Christoph eine umfassendere Lösung vorschlägt, würde eine geringfügige Korrektur seiner Antwort die Antwort vervollständigen, indem Sie volatile der Gewerkschaftserklärung hinzufügen: static const volatile union

Dies würde das Speichern und Lesen aus dem Speicher sicherstellen, was zur Bestimmung der Endlichkeit erforderlich ist. 

1
user2162550

C Code zur Überprüfung, ob ein System Little-Endian oder Big-Indian ist.

int i = 7;
char* pc = (char*)(&i);
if (pc[0] == '\x7') // aliasing through char is ok
    puts("This system is little-endian");
else
    puts("This system is big-endian");
0
S. M. AMRAN

Meine Antwort ist nicht so wie gefragt, aber es ist wirklich einfach zu finden ob Ihr System Little Endian oder Big Endian ist?

Code:

#include<stdio.h>

int main()
{
  int a = 1;
  char *b;

  b = (char *)&a;
  if (*b)
    printf("Little Endian\n");
  else
    printf("Big Endian\n");
}
0
roottraveller