web-dev-qa-db-ja.com

C ++の64ビット整数用の「標準」htonlのような関数はありますか?

私は、ある時点で64ビット整数値を使用するmemcacheプロトコルの実装に取り​​組んでいます。これらの値は、「ネットワークバイト順」で保存する必要があります。

変更を行うuint64_t htonll(uint64_t value)関数があればよかったのですが、残念ながら、存在する場合は見つけることができませんでした。

だから私は1つまたは2つの質問があります:

  • portable(Windows、Linux、AIX)これを行う標準機能はありますか?
  • そのような機能がない場合、どのように実装しますか?

基本的な実装を念頭に置いていますが、コードを移植可能にするためにコンパイル時にエンディアンネスを確認する方法がわかりません。あなたの助けはここで歓迎以上です;)

ありがとうございました。


ブライアンのソリューションのおかげで、ここに私が書いた最終的なソリューションがあります。

uint64_t htonll(uint64_t value)
{
    // The answer is 42
    static const int num = 42;

    // Check the endianness
    if (*reinterpret_cast<const char*>(&num) == num)
    {
        const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
        const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

        return (static_cast<uint64_t>(low_part) << 32) | high_part;
    } else
    {
        return value;
    }
}
60
ereOn

あなたはおそらくbswap_64を探しています。それはどこでもほとんどサポートされていると思いますが、標準とは呼びません。

値1のintを作成し、intのアドレスをchar*としてキャストし、最初のバイトの値をチェックすることで、エンディアンを簡単に確認できます。

例えば:

int num = 42;
if(*(char *)&num == 42)
{
   //Little Endian
}
else
{
   //Big Endian
} 

これを知っていれば、スワッピングを行う簡単な関数を作成することもできます。


移植可能なクロスプラットフォームであるエンディアンマクロを含むboostを常に使用することもできます。

16
Brian R. Bondy
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

テスト(1 == htonl(1))は、ハードウェアアーキテクチャがバイトスワッピングを必要とするかどうかを(実行時に悲しいことに)単純に判断します。コンパイル時にアーキテクチャが何であるかを判断する移植可能な方法はないため、この状況での移植性と同じくらい「htonl」の使用に頼ります。バイトスワップが必要な場合は、htonlを使用して一度に32ビットをスワップします(2つの32ビットワードもスワップすることを忘れないでください)。


これは、AIX、BSD、Linux、およびSolarisを含むほとんどのコンパイラーおよびオペレーティング・システム間で移植可能なスワップを実行する別の方法です。

#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif

重要な部分は、__BIG_ENDIAN__または__LITTLE_ENDIAN__;を使用することです。 __BYTE_ORDER____ORDER_BIG_ENDIAN__、または__ORDER_LITTLE_ENDIAN__ではありません。一部のコンパイラとオペレーティングシステムには、__BYTE_ORDER__とその仲間がありません。

15
deltamind106

uint64_t htobe64(uint64_t Host_64bits)uint64_t be64toh(uint64_t big_endian_64bits)を試して、その逆もできます。

5
suresh m

これはCで動作するようです。私は何か間違ったことをしましたか?

uint64_t htonll(uint64_t value) {
    int num = 42;
    if (*(char *)&num == 42) {
        uint32_t high_part = htonl((uint32_t)(value >> 32));
        uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
        return (((uint64_t)low_part) << 32) | high_part;
    } else {
        return value;
    }
}
4
pix0r

「if num == ...」のオーバーヘッドを削減するには、プリプロセッサ定義を使用します。

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif
1
user3734255