8

これは、今日のインタビューで私が提供したものです。

int is_little_endian(void)
{
    union {
        long l;
        char c;
    } u;

    u.l = 1;

    return u.c == 1;
}

私のインタビュアーは、clが同じアドレスで開始されるとは限らないため、共用体を say に変更しchar c[sizeof(long)]、戻り値を に変更する必要があると主張しましたu.c[0] == 1

組合のメンバーが同じ住所で始まるわけではないというのは正しいですか?

4

8 に答える 8

8

組合員のことはよくわかりませんでしたが、SOが助けに来ました

チェックは次のように書く方がよいでしょう。

int is_bigendian(void) {
    const int i = 1;
    return (*(unsigned char*)&i) == 0;
}

ちなみに、C FAQには両方の方法が示されています。マシンのバイト順序がビッグエンディアンかリトルエンディアンかを判断するにはどうすればよいですか?

于 2009-08-20T02:52:30.803 に答える
6

「組合のメンバーは同じ住所で始まる可能性がある」という点であなたは正しいです。標準の関連部分は (6.7.2.1 パラ 13) です。

共用体のサイズは、最大のメンバーを含めるのに十分です。いつでも最大 1 つのメンバーの値をユニオン オブジェクトに格納できます。適切に変換された共用体オブジェクトへのポインターは、そのメンバーのそれぞれ (または、メンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。

基本的に、共用体の開始アドレスは、各メンバーの開始アドレスと同じであることが保証されています。longaは a よりも大きいことが保証されていると私は信じています (まだ参照を探しています) char。これを想定する場合、ソリューションは有効である必要があります*

*整数、特に符号付き整数型の表現に関する興味深い表現があるため、まだ少し確信が持てません。6.2.6.2 条項 1 および 2 をよく読んでください。

于 2009-08-20T03:41:14.557 に答える
3

あなたのコードはおそらく多くのコンパイラで動作しますが、インタビュアーは正しいです-ユニオンまたは構造体のフィールドを整列する方法は完全にコンパイラ次第であり、この場合、charは「開始」または「終了」のいずれかに配置できます。インタビュアーのコードは疑いの余地がなく、機能することが保証されています。

于 2009-08-20T02:54:00.117 に答える
1

標準では、ユニオン内の各アイテムのオフセットは実装によって定義されているとされています。

共用体型のオブジェクトのメンバーに値が格納されている場合、そのメンバーに対応していないが他のメンバーに対応しているオブジェクト表現のバイトは、指定されていない値を取ります。 ISO / IEC 9899:1999タイプ6.5.6.2、パラ7の表現(pdfファイル)

したがって、結合内のlongに対してcharを配置する場所を選択するのはコンパイラーの責任です。これらは、同じアドレスを持つことが保証されていません。

于 2009-08-20T02:52:55.220 に答える
0

これについて質問があります...

お元気ですか

uc[0]==何でも

有効な指定:

union {
    long l;
    char c;
} u;

[0]はcharでどのように機能しますか?

私には、次のようになります。(* uc + 0)==何でも、ポインターとして扱われるucの値を考えると、がらくたになります。

(おそらく、今私が思いついたように、元の質問でいくつかのhtmlクラップコードがアンパサンドを食べた場合を除きます...)

于 2009-08-20T03:06:15.743 に答える
0

インタビュアーは正しく、これが仕様で機能することは保証されていませんが、別のタイプにポインターをキャストした後にポインターを逆参照すると未定義の動作が発生するため、他の回答も機能することが保証されません。

実際には、これ(および他の回答)は常に機能します。すべてのコンパイラーは、ポインターからユニオンへのポインターとポインターからユニオンのメンバーへのポインターの間のキャストを透過的に許可するためです。

于 2009-08-20T03:09:17.173 に答える
0

まだ言及されていない点は、整数表現にパディング ビットが含まれる可能性が標準で明示的に許可されていることです。個人的には、標準化委員会が、プログラムが特定の予想される動作を指定する簡単な方法を許可し、コンパイラがそのような仕様を尊重するか、コンパイルを拒否する必要があることを望んでいます。「整数にパディング ビットを含めてはならない」という仕様で始まったコードは、それが事実であると仮定する資格があります。

そのままでは、35 ビット値を 4 つの 9 ビット文字としてビッグエンディアン形式で格納することは (奇妙ではありますが) 完全に正当longですが、最初のバイトの LSB をパリティ ビットとして使用します。このような実装では、1a に格納するlongと、ワード全体のパリティが奇数になる可能性があるため、実装で a1をパリティ ビットに格納する必要があります。

確かに、そのような動作は奇妙ですが、パディングを使用するアーキテクチャが標準の明示的な規定を正当化するのに十分に注目に値する場合、そのようなアーキテクチャで壊れるコードは、本当に「移植可能」とは見なされません。

使用するコードunionは、単純に「ビッグ エンディアン」または「リトルエンディアン」と記述でき、パディング ビットを使用しないすべてのアーキテクチャで正しく動作するはずです。他のいくつかのアーキテクチャでは意味がありません (実際、「ビッグエンディアン」と「リトルエンディアン」という用語も意味がない可能性があります)。

于 2015-03-10T17:27:54.763 に答える
0

私が間違っている場合は修正してください。ただし、ローカル変数は 0 に初期化されていません。

これは良くありません:

union {
    long l;
    char c;
} u={0,};
于 2009-10-21T16:45:29.567 に答える