101

C でビッグ エンディアンをリトルエンディアンに変換する関数を作成する必要があります。ライブラリ関数を使用できません。

4

13 に答える 13

183

必要なのが単純なバイトスワップであると仮定して、次のようなものを試してください

符号なし16ビット変換:

swapped = (num>>8) | (num<<8);

符号なし32ビット変換:

swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
                    ((num<<8)&0xff0000) | // move byte 1 to byte 2
                    ((num>>8)&0xff00) | // move byte 2 to byte 1
                    ((num<<24)&0xff000000); // byte 0 to byte 3

これにより、バイトオーダーが位置1234から4321にスワップされます。入力が0xdeadbeefであった場合、32ビットエンディアンスワップの出力は。である可能性があります0xefbeadde

上記のコードは、マジックナンバーの代わりにマクロまたは少なくとも定数でクリーンアップする必要がありますが、うまくいけば、そのままの状態で役立ちます

編集:別の回答が指摘しているように、プラットフォーム、OS、および命令セット固有の選択肢があり、上記よりもはるかに高速です。Linuxカーネルには、エンディアンを非常にうまく処理するマクロ(たとえば、cpu_to_be32)があります。ただし、これらの選択肢は環境に固有のものです。実際には、エンディアンネスは、利用可能なアプローチを組み合わせて使用​​するのが最適です。

于 2010-02-02T06:06:08.913 に答える
112

含めることにより:

#include <byteswap.h>

マシン依存のバイトスワッピング関数の最適化されたバージョンを取得できます。次に、次の機能を簡単に使用できます。

__bswap_32 (uint32_t input)

また

__bswap_16 (uint16_t input)
于 2011-08-05T18:52:25.013 に答える
68
#include <stdint.h>


//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val ) 
{
    return (val << 8) | (val >> 8 );
}

//! Byte swap short
int16_t swap_int16( int16_t val ) 
{
    return (val << 8) | ((val >> 8) & 0xFF);
}

//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
    val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | (val >> 16);
}

//! Byte swap int
int32_t swap_int32( int32_t val )
{
    val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | ((val >> 16) & 0xFFFF);
}

更新: 64 ビット バイト スワッピングを追加

int64_t swap_int64( int64_t val )
{
    val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
    val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
    return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
}

uint64_t swap_uint64( uint64_t val )
{
    val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
    val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
    return (val << 32) | (val >> 32);
}
于 2010-04-14T12:04:21.527 に答える
18

これはかなり一般的なバージョンです。まとめていないので誤字脱字があるかもしれませんがご了承ください。

void SwapBytes(void *pv, size_t n)
{
    assert(n > 0);

    char *p = pv;
    size_t lo, hi;
    for(lo=0, hi=n-1; hi>lo; lo++, hi--)
    {
        char tmp=p[lo];
        p[lo] = p[hi];
        p[hi] = tmp;
    }
}
#define SWAP(x) SwapBytes(&x, sizeof(x));

注意:これは、速度やスペースに対して最適化されていません。これは明確 (デバッグが容易) で移植可能であることを目的としています。

更新 2018-04-04 コメンター @chux によって発見されたように、n == 0 の無効なケースをトラップする assert() を追加しました。

于 2010-02-02T08:02:17.420 に答える
8

編集:これらはライブラリ関数です。それらに従うことは、それを行う手動の方法です。

__byteswap_ushort、__byteswap_ulong、および __byteswap_uint64 を知らない人の数に、私はまったく驚かされます。確かにこれらは Visual C++ 固有のものですが、コンパイルすると x86/IA-64 アーキテクチャでおいしいコードが得られます。:)

このページから引き出されbswapた、命令の明示的な使用法を次に示します。上記の組み込みフォームは常にthis よりも高速であることに注意してください。ライブラリルーチンなしで答えを出すために追加しただけです。

uint32 cq_ntohl(uint32 a) {
    __asm{
        mov eax, a;
        bswap eax; 
    }
}
于 2010-02-02T06:26:16.453 に答える
5

冗談として:


#include <stdio.h>

int main (int argc, char *argv[])
{
    size_t sizeofInt = sizeof (int);
    int i;

    union
    {
        int x;
        char c[sizeof (int)];
    } original, swapped;

    original.x = 0x12345678;

    for (i = 0; i < sizeofInt; i++)
        swapped.c[sizeofInt - i - 1] = original.c[i];

    fprintf (stderr, "%x\n", swapped.x);

    return 0;
}
于 2010-02-02T06:47:50.963 に答える
5

4 の倍数があると仮定して、Intel 組み込み関数を使用して SSSE3 命令 pshufb を使用する方法を次に示しますint

unsigned int *bswap(unsigned int *destination, unsigned int *source, int length) {
    int i;
    __m128i mask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
    for (i = 0; i < length; i += 4) {
        _mm_storeu_si128((__m128i *)&destination[i],
        _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&source[i]), mask));
    }
    return destination;
}
于 2013-07-07T05:44:19.640 に答える
3

これはうまくいきますか / 速くなりますか?

 uint32_t swapped, result;

((byte*)&swapped)[0] = ((byte*)&result)[3];
((byte*)&swapped)[1] = ((byte*)&result)[2];
((byte*)&swapped)[2] = ((byte*)&result)[1];
((byte*)&swapped)[3] = ((byte*)&result)[0];
于 2010-08-04T21:30:49.153 に答える
2

このコード スニペットは、32 ビットのリトル エンディアン番号をビッグ エンディアン番号に変換できます。

#include <stdio.h>
main(){    
    unsigned int i = 0xfafbfcfd;
    unsigned int j;    
    j= ((i&0xff000000)>>24)| ((i&0xff0000)>>8) | ((i&0xff00)<<8) | ((i&0xff)<<24);    
    printf("unsigned int j = %x\n ", j);    
}
于 2013-07-02T11:05:49.003 に答える
1

編集:この関数は、整列された16ビットワードのエンディアンのみを交換します。UTF-16/UCS-2エンコーディングに必要なことが多い関数。編集終了。

メモリブロックのエンディアンを変更したい場合は、私の非常に高速なアプローチを使用できます。メモリ配列のサイズは8の倍数である必要があります。

#include <stddef.h>
#include <limits.h>
#include <stdint.h>

void ChangeMemEndianness(uint64_t *mem, size_t size) 
{
uint64_t m1 = 0xFF00FF00FF00FF00ULL, m2 = m1 >> CHAR_BIT;

size = (size + (sizeof (uint64_t) - 1)) / sizeof (uint64_t);
for(; size; size--, mem++)
  *mem = ((*mem & m1) >> CHAR_BIT) | ((*mem & m2) << CHAR_BIT);
}

この種の関数は、Unicode UCS-2/UTF-16ファイルのエンディアンを変更するのに役立ちます。

于 2010-02-02T09:43:07.413 に答える
1

これが私が使用している関数です-テストされ、基本的なデータ型で動作します:

//  SwapBytes.h
//
//  Function to perform in-place endian conversion of basic types
//
//  Usage:
//
//    double d;
//    SwapBytes(&d, sizeof(d));
//

inline void SwapBytes(void *source, int size)
{
    typedef unsigned char TwoBytes[2];
    typedef unsigned char FourBytes[4];
    typedef unsigned char EightBytes[8];

    unsigned char temp;

    if(size == 2)
    {
        TwoBytes *src = (TwoBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[1];
        (*src)[1] = temp;

        return;
    }

    if(size == 4)
    {
        FourBytes *src = (FourBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[3];
        (*src)[3] = temp;

        temp = (*src)[1];
        (*src)[1] = (*src)[2];
        (*src)[2] = temp;

        return;
    }

    if(size == 8)
    {
        EightBytes *src = (EightBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[7];
        (*src)[7] = temp;

        temp = (*src)[1];
        (*src)[1] = (*src)[6];
        (*src)[6] = temp;

        temp = (*src)[2];
        (*src)[2] = (*src)[5];
        (*src)[5] = temp;

        temp = (*src)[3];
        (*src)[3] = (*src)[4];
        (*src)[4] = temp;

        return;
    }

}
于 2012-08-31T15:19:03.213 に答える
-7

x86またはx86_64プロセッサで実行している場合、ビッグエンディアンはネイティブです。それで

16ビット値の場合

unsigned short wBigE = value;
unsigned short wLittleE = ((wBigE & 0xFF) << 8) | (wBigE >> 8);

32ビット値の場合

unsigned int   iBigE = value;
unsigned int   iLittleE = ((iBigE & 0xFF) << 24)
                        | ((iBigE & 0xFF00) << 8)
                        | ((iBigE >> 8) & 0xFF00)
                        | (iBigE >> 24);

これがバイトレベルの操作であることをコンパイラが認識し、バイトスワッピングコードを生成しない限り、これは最も効率的なソリューションではありません。ただし、メモリレイアウトのトリックに依存せず、非常に簡単にマクロに変換できます。

于 2010-02-02T06:05:00.353 に答える