マシンのエンディアンを決定する1行のマクロ定義はありますか。次のコードを使用していますが、マクロに変換するには長すぎます。
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char test_endian* = (unsigned char*)&test_var;
return (test_endian[0] == NULL);
}
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
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];
}
_
標準はありませんが、<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
マクロを使用できます。
プリプロセッサのみに依存する場合は、事前定義されたシンボルのリストを把握する必要があります。プリプロセッサ算術には、アドレッシングの概念はありません。
GCC Macは__LITTLE_ENDIAN__
または__BIG_ENDIAN__
を定義します
$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1
次に、#ifdef _WIN32
などのプラットフォーム検出に基づいて、プリプロセッサの条件ディレクティブを追加できます。
これが求められたものだと思います。これは、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();
に置き換えるという事実に依存していますケースシナリオ:コンパイラは最適化を行いません。正しいコードを取得できますが、少し遅くなります。
コンパイル時のテストを探していて、gccを使用している場合、次のことができます。
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
詳細については、 gcc documentation を参照してください。
can実際には、複合リテラル(C99)を使用して一時オブジェクトのメモリにアクセスします。
#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})
コンパイル時に評価するGCC。
「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);
マクロではなくインライン関数を使用します。その上、マクロのあまり良くない副作用である何かをメモリに保存する必要があります。
次のように、静的変数またはグローバル変数を使用して短いマクロに変換できます。
static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
移植可能な#defineなどに依存するものはありませんが、プラットフォームは「ホスト」エンディアンとの間で変換するための標準機能を提供します。
一般的に、ディスクへのストレージ、またはネットワークへのストレージは、[〜#〜] big [〜#〜]エンディアンの「ネットワークエンディアン」を使用し、ホストエンディアン(x86 [〜#〜] little [〜#〜]エンディアン)。 htons()
とntohs()
および友人を使用して、2つの間で変換します。
エンディアンがすべてではないことを忘れないでください-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 このような定義のニースコンパイル)。
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
これを試して:
#include<stdio.h>
int x=1;
#define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian")
int main()
{
TEST;
}
ここでの回答のほとんどは移植性がないことに注意してください。今日のコンパイラはコンパイル時にそれらの回答を評価し(最適化に依存)、特定のエンディアンに基づいて特定の値を返しますが、実際のマシンのエンディアンは異なる場合があります。エンディアンがテストされる値は、システムメモリに到達しないため、実際に実行されたコードは、実際のエンディアンに関係なく同じ結果を返します。
例 の場合、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
。
これにより、エンディアンを判断するために必要なメモリへの保存と読み取りが保証されます。
システムがリトルエンディアンかビッグインディアンかをチェックするための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");
私の答えは尋ねられたとおりではありませんが、見つけるのは本当に簡単ですシステムがリトルエンディアンまたはビッグエンディアンの場合
コード:
#include<stdio.h>
int main()
{
int a = 1;
char *b;
b = (char *)&a;
if (*b)
printf("Little Endian\n");
else
printf("Big Endian\n");
}