私は、ある時点で64ビット整数値を使用するmemcacheプロトコルの実装に取り組んでいます。これらの値は、「ネットワークバイト順」で保存する必要があります。
変更を行うuint64_t htonll(uint64_t value)
関数があればよかったのですが、残念ながら、存在する場合は見つけることができませんでした。
だから私は1つまたは2つの質問があります:
基本的な実装を念頭に置いていますが、コードを移植可能にするためにコンパイル時にエンディアンネスを確認する方法がわかりません。あなたの助けはここで歓迎以上です;)
ありがとうございました。
ブライアンのソリューションのおかげで、ここに私が書いた最終的なソリューションがあります。
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;
}
}
あなたはおそらくbswap_64
を探しています。それはどこでもほとんどサポートされていると思いますが、標準とは呼びません。
値1のintを作成し、intのアドレスをchar*
としてキャストし、最初のバイトの値をチェックすることで、エンディアンを簡単に確認できます。
例えば:
int num = 42;
if(*(char *)&num == 42)
{
//Little Endian
}
else
{
//Big Endian
}
これを知っていれば、スワッピングを行う簡単な関数を作成することもできます。
移植可能なクロスプラットフォームであるエンディアンマクロを含むboostを常に使用することもできます。
#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__
とその仲間がありません。
uint64_t htobe64(uint64_t Host_64bits)
とuint64_t be64toh(uint64_t big_endian_64bits)
を試して、その逆もできます。
これは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;
}
}
「if num == ...」のオーバーヘッドを削減するには、プリプロセッサ定義を使用します。
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif