C ++プログラムでのプログラムによるエンディアンの検出


211

ビッグエンディアンまたはリトルエンディアンのアーキテクチャを使用しているかどうかをプログラムで検出する方法はありますか?IntelまたはPPCシステムで実行され、まったく同じコードを使用できる(つまり、条件付きコンパイルがない)コードを記述できる必要があります。


4
完全を期すために、ここでは(コンパイル時に)ゲージエンディアンにしようとしておよそ誰か他の人の質問へのリンクは次のとおりです。stackoverflow.com/questions/280162/...
ファイサルVALI

14
コンパイル時にエンディアンを決定しないのはなぜですか?実行時に変更することはできません。
ephemient 2009年

3
私の知る限り、それを行うための信頼できる普遍的な方法はありません。gcc.gnu.org/ml/gcc-help/2007-07/msg00342.html
user48956

回答:


174

型のパンニングに基づく方法は好きではありません-多くの場合、コンパイラによって警告されます。それがまさに組合の目的です!

bool is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1; 
}

原則は、他の人が提案した型のケースと同等ですが、これはより明確であり、C99によると、正しいことが保証されています。gccは、ダイレクトポインターキャストよりもこれを優先します。

これは、コンパイル時にエンディアンを修正するよりもはるかに優れています-マルチアーキテクチャをサポートするOS(Mac OS Xの脂肪バイナリなど)の場合、これはppc / i386の両方で機能しますが、それ以外の場合は非常に簡単です。


51
変数に "bint"という名前を付けることはお勧めしません:)
mkb

42
これは明確に定義されていますか?C ++では、ユニオンの1つのメンバーのみが一度にアクティブにできます。つまり、1つのメンバー名を使用して割り当て、別のメンバー名を使用して読み取ることはできません(ただし、レイアウト互換の構造体には例外があります)
Faisal Vali

26
@マット:私はグーグルを調べました、そして、私には気づかなかったbintが英語で意味を持っているようです:)
David Cournapeau

17
私はこれをテストしましたが、gcc 4.0.1とgcc 4.4.1の両方で、この関数の結果はコンパイル時に決定でき、定数として扱うことができます。つまり、この関数の結果のみに依存し、問題のプラットフォームで分岐しない場合、コンパイラーはドロップします。これは、htonlの多くの実装には当てはまらない可能性があります。
全知

6
このソリューションは本当にポータブルですか?もしもCHAR_BIT != 8
zorgit

80

これは、intを設定してビットをマスクすることで実行できますが、おそらく最も簡単な方法は、組み込みのネットワークバイト変換opsを使用することです(ネットワークバイトオーダーは常にビッグエンディアンであるため)。

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

ビットをいじるのは速いかもしれませんが、この方法は単純で簡単で、失敗することはほとんど不可能です。


1
ネットワーク変換演算を使用してすべてをビッグエンディアンに変換することもできるため、Jayが遭遇する可能性のある他の問題を解決できます。
ブライアン

6
@sharptooth-低速は相対的な用語ですが、速度が本当に問題になる場合は、プログラムの開始時に一度使用し、エンディアンでグローバル変数を設定します。
Eric Petroelje、2009年

5
htonlには別の問題があります。一部のプラットフォーム(Windows?)では、Cランタイムライブラリ自体に存在せず、追加のネットワーク関連ライブラリ(ソケットなど)に存在します。他の方法でライブラリを必要としない場合、これは1つの関数だけでは非常に邪魔になります。
David Cournapeau、

7
Linux(gcc)では、htonlはコンパイル時に定数折りたたみの対象となるため、この形式の式には実行時のオーバーヘッドがまったくありません(つまり、1または0に定数折りたたみされ、デッドコードの除去により、 ifの他のブランチ)
bdonlan 2011

2
また、x86では、特にBSWAP操作をサポートするマイクロアーキテクチャーを対象とする場合、インラインアセンブラを使用してhtonlを非常に効率的に実装できます(Linux / gccでも実装できます)。
bdonlan 2011

61

この記事をご覧ください:

ここにあなたのマシンのタイプを決定するためのコードがあります

int num = 1;
if(*(char *)&num == 1)
{
    printf("\nLittle-Endian\n");
}
else
{
    printf("Big-Endian\n");
}

25
これは、intとcharが異なる長さであることに依存していることを覚えておいてください。ほとんどの場合、これは保証されません。
David Thornley、

10
私は、short intとcharが同じサイズの組み込みシステムで作業しました...通常のintもそのサイズ(2バイト)であったかどうか思い出せません。
rmeador 2009年

2
なぜこの答えはほとんど私に「おい、wtfやってるのか」と思わせない
唯一の

2
@Shillard intは少なくともその大きさである必要がありますが、charの規格がそれ以下に制限されるという要件はありません!TI F280xファミリーを見ると、CHAR_BITが16で、sizeof(int)== sizeof(char)であることがわかりますが、言及した制限は完全に良好に保たれています...
Aconcagua

5
uint8_tとuint16_tを使用しないのはなぜですか?
ロドリゴ

58

std::endianGCC 8+やClang 7+などのC ++ 20コンパイラにアクセスできる場合に使用できます。

注:2019年にstd::endian始まりまし<type_traits><bit>、2019年のケルン会議に移されました。GCC 8、Clang <type_traits>7、8、9はGCC 9+とClang 10+に搭載されてい<bit>ます。

#include <bit>

if constexpr (std::endian::native == std::endian::big)
{
    // Big endian system
}
else if constexpr (std::endian::native == std::endian::little)
{
    // Little endian system
}
else
{
    // Something else
}

5
誰もがC ++ 17と20のドラフト/プロポーザルにアクセスできますが、現在のところ、C ++ 20コンパイラーは存在していますか?
Xeverous

@Xeverousスコープの列挙が必要なだけなので、ほとんどのベンダーが以前の変更の1つとしてstdlib実装に追加すると思います。
Pharap

@Xeverous GCC 8がリリースされ、サポートされています。
Lyberta

質問に対する30以上の回答のうち、これは完全に正確な唯一の回答であるように見えます(少なくとも部分的に正しい別の回答があります)。
IInspectable

40

これは通常、コンパイル時に(特にパフォーマンス上の理由により)コンパイラーから使用可能なヘッダーファイルを使用するか、独自のヘッダーファイルを作成することによって行われます。Linuxでは、ヘッダーファイル「/usr/include/endian.h」があります。


8
これが高位投票されていないなんて信じられません。コンパイルされたプログラムの下でエンディアンが変更されるわけではないため、ランタイムテストは必要ありません。
Dolda2000

@ Dolda2000可能性としては、ARMエンディアンモードを参照してください。
Tyzoid 2016年

10
@Tyzoid:いいえ、コンパイルされたプログラムは、プロセッサがどちらの機能を備えていても、コンパイルされたエンディアンモードで常に実行されます。
Dolda2000 2016年

16

プリプロセッサがデフォルトで定義するマクロについて誰も言及していないことに驚いた。これらはプラットフォームによって異なりますが、独自のエンディアンチェックを記述するよりもはるかにクリーンです。

例えば; GCCが定義する組み込みマクロを見ると(X86-64マシン上):

:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1

PPCマシンでは、次のようになります。

:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1

:| gcc -dM -E -x c -魔法はすべての組み込みマクロを出力します)。


7
これらのマクロは、一貫して表示されません。たとえば、Redhat 6リポジトリのgcc 4.4.5では、実行しecho "\n" | gcc -x c -E -dM - |& grep -i 'endian'ても何も返されませんが、/usr/sfw/binSolarisのgcc 3.4.3(とにかく)はこれらの行に沿った定義を持っています。VxWorks Tornado(gcc 2.95)-vs- VxWorks Workbench(gcc 3.4.4)でも同様の問題が発生しました。
ブライアンヴァンデンバーグ

15

Ehm ...コンパイラがテストを最適化し、固定の結果を戻り値として出力することに誰も気付いていないことに驚いています。これにより、上記のすべてのコード例が事実上役に立たなくなります。返されるのは、コンパイル時のエンディアンだけです。そして、はい、上記の例をすべてテストしました。以下は、MSVC 9.0(Visual Studio 2008)の例です。

純粋なCコード

int32 DNA_GetEndianness(void)
{
    union 
    {
        uint8  c[4];
        uint32 i;
    } u;

    u.i = 0x01020304;

    if (0x04 == u.c[0])
        return DNA_ENDIAN_LITTLE;
    else if (0x01 == u.c[0])
        return DNA_ENDIAN_BIG;
    else
        return DNA_ENDIAN_UNKNOWN;
}

分解

PUBLIC  _DNA_GetEndianness
; Function compile flags: /Ogtpy
; File c:\development\dna\source\libraries\dna\endian.c
;   COMDAT _DNA_GetEndianness
_TEXT   SEGMENT
_DNA_GetEndianness PROC                 ; COMDAT

; 11   :     union 
; 12   :     {
; 13   :         uint8  c[4];
; 14   :         uint32 i;
; 15   :     } u;
; 16   : 
; 17   :     u.i = 1;
; 18   : 
; 19   :     if (1 == u.c[0])
; 20   :         return DNA_ENDIAN_LITTLE;

    mov eax, 1

; 21   :     else if (1 == u.c[3])
; 22   :         return DNA_ENDIAN_BIG;
; 23   :     else
; 24   :        return DNA_ENDIAN_UNKNOWN;
; 25   : }

    ret
_DNA_GetEndianness ENDP
END

おそらく、この関数だけのコンパイル時最適化をオフにすることは可能ですが、私にはわかりません。それ以外の場合、移植性はありませんが、アセンブリでハードコード化することはおそらく可能です。そして、それでも最適化される可能性があります。それは私がいくつかの本当にひどいアセンブラが必要だと思うようになり、すべての既存のCPU /命令セットに同じコードを実装します。

また、ここの誰かは、実行時にエンディアンは変化しないと述べました。違う。そこにはバイエンディアンのマシンがあります。それらのエンディアンは、実行中に変化する可能性があります。また、リトルエンディアンとビッグエンディアンだけでなく、他のエンディアン(単語)もあります。

私は嫌いで、同時にコーディングが大好きです...


11
とにかく、別のプラットフォームで実行するために再コンパイルする必要はありませんか?
bobobobo 2011

2
これはMSVCでうまく機能しますが、すべての状況ですべてのGCCバージョンに対応するわけではありません。したがって、重要なループ内の「実行時チェック」は、コンパイル時に正しく分岐されない場合があります。100%の保証はありません。
シアン

21
ビッグエンディアンのx86プロセッサなどはありません。ARMやMIPSなどのバイエンディアンプロセッサでUbuntuを実行している場合でも、ELF実行可能ファイルは常にビッグ(MSB)またはリトル(LSB)エンディアンです。ビエンディアン実行可能ファイルを作成できないため、実行時チェックは不要です。
Fabel、

4
この方法の使用に最適化をオフにするには「揮発性の組合...」これは「U」のどこかに変更することができ、データをロードする必要があることをコンパイラに伝えます
mishmashru

1
この関数が実行時にオプティマイザが計算しているものとは異なる値を返す場合、オプティマイザにバグがあることを意味します。コンパイル中にオプティマイザによって(プログラム全体で)行われた明白な仮定にもかかわらず、それらの少なくとも1つと互換性がないように思われるにもかかわらず、エンディアンが異なる2つの異なるアーキテクチャで移植可能に実行できるコンパイル済みの最適化バイナリコードの例があると言っていますか?アーキテクチャ?
スコット

13

int変数を宣言します。

int variable = 0xFF;

次に、char *ポインターを使用して、そのさまざまな部分を調べ、それらの部分の内容を確認します。

char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;

どちらが0xFFバイトを指しているかに応じて、エンディアンを検出できます。これにはsizeof(int)> sizeof(char)が必要ですが、議論されているプラ​​ットフォームには間違いなく当てはまります。


8

詳細については、このcodeprojectの記事「エンディアンネスの基本概念」をご覧ください

実行時にエンディアン型を動的にテストする方法は?

Computer Animation FAQで説明されているように、次の関数を使用して、コードがリトルエンディアンシステムまたはビッグエンディアンシステムで実行されているかどうかを確認できます。

#define BIG_ENDIAN      0
#define LITTLE_ENDIAN   1
int TestByteOrder()
{
   short int word = 0x0001;
   char *byte = (char *) &word;
   return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}

このコードは、値0001hを16ビット整数に割り当てます。次に、整数値の最初の(最下位)バイトを指すようにcharポインターが割り当てられます。整数の最初のバイトが0x01hの場合、システムはリトルエンディアンです(0x01hは最下位または最下位アドレスにあります)。0x00hの場合、システムはビッグエンディアンです。


6

C ++の方法はboostを使用することでした。プリプロセッサのチェックとキャストは、非常に徹底的にテストされたライブラリ内で区分化されています。

Predef Library(boost / predef.h)は4種類のエンディアンを認識します。

エンディアンライブラリは、 C ++標準に提出される予定、とエンディアン機密データに対する操作のさまざまなサポートしていました。

上記の回答で述べたように、エンディアンネスはc ++ 20の一部になります。


1
ちなみに、「4種類のエンディアン」のリンクは壊れています
レミー・ルボー

修正および作成されたwiki
fuzzyTew 2018年

5

PPCとIntelのプラットフォームに移植されたフレームワークを使用している場合を除き、PPCとIntelのプラットフォームはハードウェアアーキテクチャ、パイプライン、バスなどがまったく異なるため、条件付きコンパイルを行う必要があります。これにより、アセンブリコードが完全に異なります二つ。

エンディアンを見つけるには、次のようにします。

short temp = 0x1234;
char* tempChar = (char*)&temp;

tempCharが0x12または0x34のいずれかになると、エンディアンがわかります。


3
これは、保証されていない正確に2バイトのshortに依存しています。
シャープトゥース、2009年

3
それは質問で与えられた2つのアーキテクチャに基づいていますが、かなり安全な賭けです。
テミン、

8
インクルードしてstdint.hint16_tショートが別のプラットフォームで異なることに対する将来の証明に使用します。
Denise Skidmore

4

私はこのようなことをします:

bool isBigEndian() {
    static unsigned long x(1);
    static bool result(reinterpret_cast<unsigned char*>(&x)[0] == 0);
    return result;
}

これらの線に沿って、一度だけ計算を行う時間効率の良い関数を取得します。


インライン化できますか?インラインで静的変数の複数のメモリブロックが発生するかどうか
不明

4

上記のように、結合トリックを使用します。

ただし、上記のアドバイスにはほとんど問題がありません。最も顕著なのは、ほとんどのアーキテクチャで非境界整列メモリアクセスが遅いことで有名です。一部のコンパイラは、単語境界でない限り、このような定数述語をまったく認識しません。

単なるエンディアンテストは退屈なので、ホストアーキテクチャに関係なく、仕様に従って任意の整数の入力/出力を反転する(テンプレート)関数を次に示します。

#include <stdint.h>

#define BIG_ENDIAN 1
#define LITTLE_ENDIAN 0

template <typename T>
T endian(T w, uint32_t endian)
{
    // this gets optimized out into if (endian == host_endian) return w;
    union { uint64_t quad; uint32_t islittle; } t;
    t.quad = 1;
    if (t.islittle ^ endian) return w;
    T r = 0;

    // decent compilers will unroll this (gcc)
    // or even convert straight into single bswap (clang)
    for (int i = 0; i < sizeof(r); i++) {
        r <<= 8;
        r |= w & 0xff;
        w >>= 8;
    }
    return r;
};

使用法:

特定のエンディアンからホストに変換するには、次を使用します。

host = endian(source, endian_of_source)

ホストエンディアンから特定のエンディアンに変換するには、次のコマンドを使用します。

output = endian(hostsource, endian_you_want_to_output)

結果のコードは、clangでハンドアセンブリを書くのと同じくらい高速ですが、gccでは少し遅くなりますが(すべてのバイトで&、<<、>>、|展開される)、それでもまともです。



4

使用しないでくださいunion

C ++では、unionsによる型パンニングは許可されていません。
最後に書き込まれたフィールドではない共用体フィールドからの読み取りは、未定義の動作です。
多くのコンパイラはこれを拡張機能としてサポートしていますが、言語はこれを保証しません。

詳細については、この回答を参照してください:

https://stackoverflow.com/a/11996970


移植可能であることが保証されている有効な回答は2つだけです。

C ++ 20をサポートするシステムにアクセスできる場合、最初の答えはヘッダー
から使用することです。 std::endian<type_traits>

(執筆時点では、C ++ 20はまだリリースされていませんが、何かがstd::endianのインクルードに影響を与えない限り、これはC ++ 20以降のコンパイル時にエンディアンをテストするための推奨される方法です。)

C ++ 20以降

constexpr bool is_little_endian = (std::endian::native == std::endian::little);

C ++ 20以前は、唯一の有効な答えは、整数を格納してから、型パンニングによって最初のバイトを検査することです。s
の使用とは異なりunion、これはC ++の型システムで明示的に許可されています。

これは、最適な移植性のためにことを覚えておくことも重要ですstatic_cast、使用しなければならない
のでreinterpret_cast、実装が定義されています。

プログラムが次のタイプの1つ以外のglvalueを介してオブジェクトの格納された値にアクセスしようとした場合の動作は定義されていません:... a charまたはunsigned chartype。

C ++ 11以降

enum class endianness
{
    little = 0,
    big = 1,
};

inline endianness get_system_endianness()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01) ? endianness::little : endianness::big;
}

C ++ 11以降(列挙型なし)

inline bool is_system_little_endian()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

C ++ 98 / C ++ 03

inline bool is_system_little_endian()
{
    const int value = 0x01;
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

3
union {
    int i;
    char c[sizeof(int)];
} x;
x.i = 1;
if(x.c[0] == 1)
    printf("little-endian\n");
else    printf("big-endian\n");

これは別の解決策です。Andrew Hareのソリューションに似ています。


3

未テストですが、私の心の中で、これはうまくいくでしょうか?リトルエンディアンの場合は0x01、ビッグエンディアンの場合は0x00になるためです。

bool runtimeIsLittleEndian(void)
{
 volatile uint16_t i=1;
 return  ((uint8_t*)&i)[0]==0x01;//0x01=little, 0x00=big
}

3

宣言:

私の最初の投稿は「コンパイル時」と誤って宣言されています。現在のC ++標準では不可能です。constexprは、関数が常にコンパイル時の計算を行うことを意味しません。訂正してくれたRichard Hodgesに感謝します。

コンパイル時、非マクロ、C ++ 11 constexprソリューション:

union {
  uint16_t s;
  unsigned char c[2];
} constexpr static  d {1};

constexpr bool is_little_endian() {
  return d.c[0] == 1;
}

2
uint8_tでunsigned charを使用した特別な理由はありますか?
ケビン

0ランタイムオーバーヘッド...私はそれが好きです!
hanshenrik 2015

たぶん、これはターゲットではなくビルドマシンのエンディアンを検出しますか?
2015年

2
このUBはC ++ではありませんか?
rr- 2016

6
これはconstexprのコンテキストでは合法ではありません。直接初期化されていないユニオンのメンバーにはアクセスできません。プリプロセッサの魔法がなければ、コンパイル時にエンディアンを合法的に検出する方法はありません。
Richard Hodges

2

また、ブーストエンディアンにあるブーストヘッダーファイルのようなものを使用して、プリプロセッサ経由でこれを行うこともできます。


1

エンディアンヘッダーがGCCのみでない限り、使用できるマクロが提供されます。

#include "endian.h"
...
if (__BYTE_ORDER == __LITTLE_ENDIAN) { ... }
else if (__BYTE_ORDER == __BIG_ENDIAN) { ... }
else { throw std::runtime_error("Sorry, this version does not support PDP Endian!");
...

これらはでない__BYTE_ORDER____ORDER_LITTLE_ENDIAN____ORDER_BIG_ENDIAN__
Xeverous 2018年

1

条件付きコンパイルが必要ない場合は、エンディアンに依存しないコードを記述するだけです。次に例を示します(Rob Pikeから取得):

ディスク上のリトルエンディアンに格納されている整数を、エンディアンに依存しない方法で読み取ります。

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

マシンのエンディアンを考慮に入れようとする同じコード:

i = *((int*)data);
#ifdef BIG_ENDIAN
/* swap the bytes */
i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) | (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
#endif

なんて素晴らしいアイデアでしょう!そして今、あなたの整数をネットワークソケット経由で未知のデバイスに転送しましょう。
Maksym Ganenko

@MaksymGanenkoコメントはありません。それは皮肉ですか?私はないシリアライズされたデータのエンディアンを指定しないことを示唆しています。データを受信するマシンのエンディアンに依存するコードを記述しないことをお勧めします。
fjardon

@MaksymGanenko反対票を投じた場合、答えが間違っている理由を説明できます。少なくとも、潜在的な読者が私の答えに従わないほうがよい理由を理解できるようにしてください。
fjardon


0

これはどう?

#include <cstdio>

int main()
{
    unsigned int n = 1;
    char *p = 0;

    p = (char*)&n;
    if (*p == 1)
        std::printf("Little Endian\n");
    else 
        if (*(p + sizeof(int) - 1) == 1)
            std::printf("Big Endian\n");
        else
            std::printf("What the crap?\n");
    return 0;
}

0

これは別のCバージョンです。これは、wicked_cast()C99ユニオンリテラルと非標準の__typeof__演算子を介してインライン型パンニングのために呼び出されるマクロを定義します。

#include <limits.h>

#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif

#define wicked_cast(TYPE, VALUE) \
    (((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)

_Bool is_little_endian(void)
{
    return wicked_cast(unsigned char, 1u);
}

整数が1バイト値の場合、エンディアンは意味がなく、コンパイル時エラーが生成されます。


0

Cコンパイラ(少なくとも私が知っているすべての人)がエンディアンを機能させる方法は、コンパイル時に決定する必要があります。(ARM och MIPSのような)バイエンディアンプロセッサでも、コンパイル時にエンディアンを選択する必要があります。さらに、エンディアンは、実行可能ファイル(ELFなど)のすべての一般的なファイル形式で定義されています。ビアンディアンコードのバイナリblobを作成することは可能ですが(一部のARMサーバーエクスプロイトでは)?おそらく、アセンブリで行う必要があります。


-1

Coriianderが指摘したように、これらのコードのほとんど(すべてではない)はコンパイル時に最適化されるため、生成されたバイナリは実行時に「エンディアン」をチェックしません。

特定の実行可能ファイルが2つの異なるバイトオーダーで実行されるべきではないことが確認されていますが、それが常に当てはまるかどうかはわかりません。コンパイル時に確認するのはハックのようです。だから私はこの関数をコーディングしました:

#include <stdint.h>

int* _BE = 0;

int is_big_endian() {
    if (_BE == 0) {
        uint16_t* teste = (uint16_t*)malloc(4);
        *teste = (*teste & 0x01FE) | 0x0100;
        uint8_t teste2 = ((uint8_t*) teste)[0];
        free(teste);
        _BE = (int*)malloc(sizeof(int));
        *_BE = (0x01 == teste2);
    }
    return *_BE;
}

MinGWは、他のコードをここで最適化しましたが、このコードを最適化できませんでした。これは、小さいバイトメモリに割り当てられた「ランダム」値をそのまま(少なくとも7ビット)にしておくため、コンパイラはそのランダム値が何であるかを認識できず、最適化されないためだと思います。離れた機能。

また、チェックが1回だけ実行され、戻り値が次のテストのために保存されるように、関数をコーディングしました。


2バイトの値を処理するために4バイトを割り当てるのはなぜですか?なぜ不確定値をマスクするの0x7FEですか?なぜ使用malloc()するのですか?それは無駄です。そして_BE、(わずかではありますが)メモリリークと発生するのを待っている競合状態です。結果を動的にキャッシュすることの利点は、問題に値しません。代わりに私はこのようなことをします:static const uint16_t teste = 1; int is_little_endian() { return (0x01 == ((uint8_t*)&teste)[0]); } int is_big_endian() { return (0x01 == ((uint8_t*)&teste)[1]); }シンプルで効果的で、実行時に実行する作業がはるかに少なくなります。
レミールボー・

@RemyLebeau、私の答えの要点は、コンパイラーによって最適化されないコードを生成することでした。確かに、コードははるかに単純ですが、最適化がオンになっていると、コンパイル後は定数ブール値になります。私の答えで述べたように、同じ実行可能ファイルが両方のバイトオーダーで実行されるようにCコードをコンパイルする方法があるかどうかは実際にはわかりません。また、実行時にチェックできるかどうかも知りたくて最適化がオンになっているにもかかわらず。
Tex Killer

@TexKillerでは、なぜコードの最適化を無効にしないのですか?使用してvolatile、または#pragma、など
レミールボー・

@RemyLebeau、私はその時それらのキーワードを知りませんでした、そして私が知っていることでコンパイラの最適化を防ぐためにそれを小さな挑戦として単に取りました。
Tex Killer、

-1

それを決定する迅速で標準的な方法はありませんが、これはそれを出力します:

#include <stdio.h> 
int main()  
{ 
   unsigned int i = 1; 
   char *c = (char*)&i; 
   if (*c)     
       printf("Little endian"); 
   else
       printf("Big endian"); 
   getchar(); 
   return 0; 
} 

-1

エンディアンネス -Cレベルのコードの図を参照してください。

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANNESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANNESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 

-2

私は教科書を読んでいました:コンピューターシステム:プログラマーの視点」を読んでいましたが、Cプログラムでこれがどのエンディアンかを判別するのに問題があります。

ポインターの機能を使用して、次のようにしました。

#include <stdio.h>

int main(void){
    int i=1;
    unsigned char* ii = &i;

    printf("This computer is %s endian.\n", ((ii[0]==1) ? "little" : "big"));
    return 0;
}

intは 4つのバイトを占め、そしてチャーはわずか1バイトを占めます。我々は、使用できる文字ポインタをポイントにINTコンピュータがリトルエンディアンである場合、このように値1とチャーことチャーポインタそうでなければ、その値は0でなければならず、値1とされる点。


これは、int32tを使用することで改善されます。
シャトル87 2014

1
^ひっくり返す場合、ここでの最良の方法はint16_fast_tです。そして、@ Archimedes520の現在のコードは、intがネイティブのint8である
Arch
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.