4

私には2つcharのがあり、それらをビット単位で「ステッチ」したいと思います。
例えば:

char c1 = 11; // 0000 1011
char c2 = 5;  // 0000 0101
short int si = stitch(c1, c2); // 0000 1011 0000 0101

したがって、私が最初に試したのはビット演算子を使用したものです。

short int stitch(char c1, char c2)
{
    return (c1 << 8) | c2;
}

しかし、これは機能しません。私は次のようにshortなりc2ます... (1)なぜですか?
(しかし:c1そしてc2私の実際のアプリでは負の数です...多分これは問題の一部ですか?)

だから、私の2番目の解決策はunion:を使用することでした

union stUnion
{
    struct
    {
         char c1;
         char c2;
    }
    short int si;
}

short int stitch(char c1, char c2)
{
    stUnion u;
    u.c1 = c1;
    u.c2 = c2;
    return u.si;
}

これは私が望むように機能します...私は思います

(2)最良/最速の方法は何ですか?

ありがとう!

4

5 に答える 5

7

このunion方法は、せいぜい実装で定義されています(実際には、かなり確実に機能しますが、の形式はsiプラットフォームのエンディアンによって異なります)。

ビット単位の方法の問題は、ご想像のとおり、負の数です。負の数は、先頭の1のチェーンで表されます。たとえば、-5は

1111 1011

これをキャストしintたりunsigned int、キャストしたりすると、

1111 1111 1111 … 1111 1011

ORが適用されると、これらすべての1は左シフトされたデータをかき消します。

この問題を解決するには、シフトする前にcharsをtoにキャストしてからtoにキャストunsigned charしますint(オーバーフロー、またはオーバーフローの可能性の出現を防ぐため)。

short int stitch(char c1, char c2)
{
    return ( (int) (unsigned char) c1 << 8) | (unsigned char) c2;
}

または、引数のタイプを自由に変更でき、含めることができる場合は<cstdint>

uint16_t stitch( uint8_t c1, uint8_t c2)
{
    return ( (int) c1 << 8 ) | c2;
}
于 2010-08-15T10:36:51.443 に答える
3

$ 5.8 / 1の状態-「オペランドは整数型または列挙型であり、汎整数拡張が実行されます。結果の型は、プロモートされた左側のオペランドの型です。右側のオペランドが負の場合、またはそれ以上の場合、動作は定義されません。プロモートされた左オペランドのビット単位の長さに。」

したがって、c1をunsigned intに型キャストしてから、C2とビット単位のORをとってみてください。また、出力をunsignedintとして返します。charsはintにプロモートされますが、「unsignedint」になりたいです。

于 2010-08-15T10:23:25.320 に答える
2

その理由は、ビット単位のORを実行する前にc2最初にプロモートされるためです。これにより、符号拡張が行われます(charが符号付きで、負の値を保持できると想定)。int

char x1 = -2; // 1111 1110
char x2 = -3; // 1111 1101

short int si = stitch(c1, c2); // 1111 1111 1111 1101

x2プロモートの表現intは(少なくとも)1バイトでいっぱいな1ので、x1前にシフトアップしたゼロビットを上書きします。最初にキャストできますunsigned char。2の補数表現では、最下位バイトのビットパターンは変更されません。厳密に必要というわけではありませんが、一貫性を保つためにキャストc1することunsigned charもできます(shortが2バイトの場合、c1それらの2バイトを超えて符号拡張されていても問題ありません) 。

short int stitch(char c1, char c2) {
    return ((unsigned char)c1 << 8) | (unsigned char)c2;
}
于 2010-08-15T10:35:41.680 に答える
1

シフト/またはメソッドは、一度修正されると、バイト順序に依存しないため、よりクリーンになります。

それとは別に、ストアからロードへの転送(STLF)の問題により、最近の多くのCPUではユニオン方式の速度が遅くなる可能性があります。値をメモリに書き込んでから、それをさまざまなデータ型として読み戻します。これが発生した場合、多くのCPUはデータをロードに迅速に送信できません。ロードは、ストアが完全に完了する(リタイアされる)まで待機し、そのデータをL1キャッシュに書き込む必要があります。

バレルシフタがなく(8シフトには8回の操作が必要)、68000などの単純な順序どおりの実行を使用する非常に古いCPUでは、ユニオン方式の方が高速な場合があります。

于 2010-08-15T11:13:44.100 に答える
-1

そのためにユニオンを使用しないでください。ユニオンフィールドを同時に使用しないでください。ユニオンにメンバーAとメンバーBがある場合は、AとBが無関係であることを考慮する必要があります。これは、コンパイラーが任意の場所にパディングを自由に追加できるためです(構造体の先頭を除く)。もう1つの問題は、バイトオーダー(リトルエンディアン/ビッグエンディアン)です。

//編集上記の「ユニオンルール」には例外があります。フロンにあり、同じレイアウトを持つこれらのメンバーを同時に使用できます。すなわち

union {
    struct {
        char c;
        int i;
        short s;
    } A;
    struct {
        char c;
        int i;
        char c1;
        char c2;
    } B;
};

AcとAiはBcとBiと同時に使用できます

于 2010-08-15T10:40:44.370 に答える