web-dev-qa-db-ja.com

Cエンディアンまたはリトルエンディアンのマシンを決定するマクロ定義?

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

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

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

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
94
Christoph

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];
}
_
44
caf

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

実行時にエンディアンを検出するには、メモリを参照できる必要があります。標準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マクロを使用できます。

27
Norman Ramsey

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

GCC Mac__LITTLE_ENDIAN__または__BIG_ENDIAN__を定義します

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

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

19
Gregory Pakosz

これが求められたものだと思います。これは、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();に置き換えるという事実に依存していますケースシナリオ:コンパイラは最適化を行いません。正しいコードを取得できますが、少し遅くなります。

15
ggpp23

コンパイル時のテストを探していて、gccを使用している場合、次のことができます。

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

詳細については、 gcc documentation を参照してください。

9
Jezz

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

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

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

8
u0b34a0f6ae

「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);
7
BlueChip

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

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

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

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

一般的に、ディスクへのストレージ、またはネットワークへのストレージは、[〜#〜] big [〜#〜]エンディアンの「ネットワークエンディアン」を使用し、ホストエンディアン(x86 [〜#〜] little [〜#〜]エンディアン)。 htons()ntohs()および友人を使用して、2つの間で変換します。

5
Will

エンディアンがすべてではないことを忘れないでください-charのサイズは8ビット(DSPなど)ではない場合があり、2の補数の否定は保証されません(Crayなど)。 、また、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
}

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

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

これを試して:

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

   TEST;
}
3
Prasoon Saurav

ここでの回答のほとんどは移植性がないことに注意してください。今日のコンパイラはコンパイル時にそれらの回答を評価し(最適化に依存)、特定のエンディアンに基づいて特定の値を返しますが、実際のマシンのエンディアンは異なる場合があります。エンディアンがテストされる値は、システムメモリに到達しないため、実際に実行されたコードは、実際のエンディアンに関係なく同じ結果を返します。

の場合、ARM Cortex-M3では、実装されたエンディアンはステータスビットAIRCR.ENDIANNESSに反映され、コンパイラはコンパイル時にこの値を知ることができません。

ここで提案されているいくつかの回答のコンパイル出力:

https://godbolt.org/z/GJGNE2 for this answer、

https://godbolt.org/z/Yv-pyJ for this answerなど。

これを解決するには、volatile修飾子を使用する必要があります。 Yogeesh H Tの答えは、今日の実際の使用に最も近いものですが、Christophはより包括的なソリューションを提案しているため、彼の answer を少し修正すると、答えが完全になり、volatileをユニオン宣言に:static const volatile union

これにより、エンディアンを判断するために必要なメモリへの保存と読み取りが保証されます。

2
user2162550

システムがリトルエンディアンかビッグインディアンかをチェックするための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");
0
S. M. AMRAN

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

コード:

#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