114

マシンのエンディアンを決定するための 1 行のマクロ定義はありますか。次のコードを使用していますが、マクロに変換するには時間がかかりすぎます。

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

    return (test_endian[0] == 0);
}
4

21 に答える 21

108

任意のバイト オーダーをサポートするコードは、次のファイルに配置できますorder32.h

#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

リトルエンディアンシステムを確認するには、次の方法を使用します

O32_HOST_ORDER == O32_LITTLE_ENDIAN
于 2010-01-20T16:39:01.020 に答える
52

C99 複合リテラルをサポートするコンパイラがある場合:

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

また:

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

ただし、一般的には、ホスト プラットフォームのエンディアンに依存しないコードを作成するようにしてください。


のホスト エンディアンに依存しない実装の例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];
}
于 2010-01-20T10:19:41.610 に答える
45

標準はありませんが、含む多くのシステムで<endian.h>は、探すべきいくつかの定義が得られます。

于 2010-01-20T09:49:27.667 に答える
27

実行時にエンディアンを検出するには、メモリを参照できる必要があります。標準 C に固執する場合、メモリ内の変数を宣言するにはステートメントが必要ですが、値を返すには式が必要です。単一のマクロでこれを行う方法がわかりません。これが、gcc に拡張機能がある理由です :-)

.h ファイルが必要な場合は、次のように定義できます。

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

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

その後、ENDIANNESSマクロを自由に使用できます。

于 2010-01-20T09:52:01.487 に答える
19

プリプロセッサのみに依存したい場合は、事前定義されたシンボルのリストを把握する必要があります。プリプロセッサの算術演算には、アドレス指定の概念がありません。

Mac 上のGCCは__LITTLE_ENDIAN__、または__BIG_ENDIAN__

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

#ifdef _WIN32次に、プラットフォームの検出などに基づいて、プリプロセッサの条件付きディレクティブを追加できます。

于 2010-01-20T09:53:45.880 に答える
15

これが求められていたものだと思います。これは、msvc の下のリトル エンディアン マシンでのみテストしました。誰かがビッグエンディアンのマシンで確認してください。

    #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

#if補足として (コンパイラ固有)、アグレッシブなコンパイラを使用すると、「デッド コードの除去」最適化を使用して、次のようにコンパイル時と同じ効果を得ることができます。

    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; // ?
    }

上記は、コンパイラがコンパイル時に定数値を認識し、内部のコードを完全に削除し、コードを次のようにif (false) { ... }置き換えるという事実に依存しています。if (true) { foo(); }foo();

于 2012-02-14T19:41:29.663 に答える
8

実際、複合リテラル (C99) を使用して、一時オブジェクトのメモリにアクセスできます

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

コンパイル時に評価する GCC。

于 2013-01-11T06:31:30.870 に答える
7

「C ネットワーク ライブラリ」は、エンディアンを処理する関数を提供します。つまり、htons()、htonl()、ntohs()、および ntohl() ... ここで、n は「ネットワーク」(つまり、ビッグエンディアン) であり、h は「ホスト」(つまり、実行しているマシンのエンディアン) です。コード)。

これらの明白な「関数」は (一般的に) マクロとして定義されているため [<netinet/in.h> を参照]、それらを使用するための実行時のオーバーヘッドはありません。

次のマクロは、これらの「関数」を使用してエンディアンを評価します。

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

加えて:

システムのエンディアンを知る必要があるのは、エンディアンが不明な別のシステムによって読み込まれる可能性のある変数を [ファイル/その他に] 書き出すときだけです (クロスプラットフォームの互換性のため)。 ) ...次のような場合は、エンディアン関数を直接使用することをお勧めします。

#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);
于 2013-06-12T00:27:45.623 に答える
6

マクロではなくインライン関数を使用してください。その上、何かをメモリに保存する必要がありますが、これはマクロのあまり良くない副作用です。

次のように、静的変数またはグローバル変数を使用して短いマクロに変換できます。

static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
于 2010-01-20T09:48:59.873 に答える
5

移植可能な #define や依存するものはありませんが、プラットフォームは「ホスト」エンディアンとの間で変換するための標準関数を提供します。

一般に、ディスクまたはネットワークへのストレージは、 BIGエンディアンである「ネットワーク エンディアン」を使用し、ホスト エンディアン (x86 ではLITTLEエンディアン) を使用してローカル計算を行います。htons()andと friends を使用しntohs()て、2 つの間で変換します。

于 2010-01-20T09:53:40.657 に答える
4

エンディアンがすべてではないことを忘れないでください - のサイズはchar8 ビットではない可能性があり (例: DSP)、2 の補数の否定は保証されていません (例: Cray)、厳密な位置合わせが必要な場合があります (例: SPARC、ARM も中間に飛び出します)。 -整列されていない場合のエンディアン)など

代わりに、特定のCPU アーキテクチャをターゲットにすることをお勧めします。

例えば:

#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
}

残念ながら、このソリューションはコンパイラ固有の定義に依存するため、ウルトラポータブルではないことに注意してください (標準はありませんが、そのような定義の優れたコンパイルがあります)

于 2016-11-02T15:44:48.410 に答える
4
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
于 2012-02-13T17:11:39.593 に答える
3

これを試して:

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

   TEST;
}
于 2010-01-20T09:54:13.043 に答える
3

プリプロセッサ #defines をダンプする場合

gcc -dM -E - < /dev/null
g++ -dM -E -x c++ - < /dev/null

通常、あなたに役立つものを見つけることができます。コンパイル時ロジック付き。

#define __LITTLE_ENDIAN__ 1
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__

ただし、コンパイラによって定義が異なる場合があります。

于 2019-11-14T17:07:42.263 に答える
1

この質問はcppでも実際にあるので、ここで質問しました。

それだけ#if __cplusplus > 201703L

#include <bit>
#include <iostream>

using namespace std;

int main()
{
    if constexpr (endian::native == endian::big)
        cout << "big-endian";
    else if constexpr (endian::native == endian::little)
        cout << "little-endian";
    else
        cout << "mixed-endian";
}

詳細情報: https://en.cppreference.com/w/cpp/types/endian

于 2021-12-08T02:05:00.910 に答える
-1

システムがリトル エンディアンかビッグ インディアンかをチェックするための C コード。

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");
于 2017-01-07T05:21:44.980 に答える
-1

私の答えは尋ねられたとおりではありませんが、システムがリトルエンディアンかビッグエンディアンかを見つけるのは本当に簡単ですか?

コード:

#include<stdio.h>

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

  b = (char *)&a;
  if (*b)
    printf("Little Endian\n");
  else
    printf("Big Endian\n");
}
于 2016-04-13T15:37:59.273 に答える