意見るスプライシングバリアンpunning C++?
-
19-08-2019 - |
質問
私は約条約はタイプpunningポインタの列可能です。ここでは利用いので、瞬間:
計算の簡単な32ビットチェックサム上のバイナリー blobによるデータの処理としての配列の32ビット整数(お知らその全長は複数の4)、そして総括すべての値を無視してオーバーフロー.
私は期待どの機能を眺めるようになります:
uint32_t compute_checksum(const char *data, size_t size)
{
const uint32_t *udata = /* ??? */;
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
checksum += udata[i];
return udata;
}
現在、質問しているのは、あなたは何を考える"ベスト"への転換 data
へ udata
?
Cスタイルのキャスト?
udata = (const uint32_t *)data
C++キャストを想定したすべてのポインタの転換でき?
udata = reinterpret_cast<const uint32_t *>(data)
C++キャストとの間の任意のポインタ型を使用中間体 void*
?
udata = static_cast<const uint32_t *>(static_cast<const void *>(data))
キャスト通りです。
union {
const uint32_t *udata;
const char *cdata;
};
cdata = data;
// now use udata
いう実感がこすということではありません100%の携帯液かもしれませんが、同じだけを利用すので、小さなセットプラットフォームがこの作品についunalignedメモリアクセスコンパイラの前提にポインタをアンチエイリアス).何をお勧めになりますか。
解決
どのC++の標準に関 litb"の答えは完全に正確で最もブランドだ。鋳造 const char *data
へ const uint3_t *
, し、それを介してC-スタイルキャスト static_cast
, や reinterpret_cast
, 休憩の際の厳しいエイリアシングルを参照 理解の厳しいエイリアシング).場合はコンパイルとのフルの最適化、ある良い機会なので、コードは右ものです。
鋳造を通じて組合などのlitb my_reint
)の最良の解決策ではな技術的に違反する書き込む場合は、組合を通じて一人の委員は、読んでて、その結果として定義されます。しかし、実質的にすべてのコンパイラを支え、その結果としての想される結果です。場合は絶対にい標準に合わせて100%でもちょこっとビットシフト方法です。その他、私のお勧めは鋳造品を組合を起こす可能性が高くすくなります。
他のヒント
無視の効率化、簡単のため、コードの思い:
#include <numeric>
#include <vector>
#include <cstring>
uint32_t compute_checksum(const char *data, size_t size) {
std::vector<uint32_t> intdata(size/sizeof(uint32_t));
std::memcpy(&intdata[0], data, size);
return std::accumulate(intdata.begin(), intdata.end(), 0);
}
もうlitb最後の答えは、このシフトの各char、外からcharが署名したかというニーズの追加マスク:
checksum += ((data[i] && 0xFF) << shift[i % 4]);
Type punningは潜在的な問題については、私はあまり好きではないのですがタイプシャレなしています。ない場合を含ポインタの異なる種類の、などのコンパイラがなエイリアスは、いずれも、保守プログラマの方はご複数のstatic_castsによる。
したいという場合などに行くのメモリとします。
uint32_t compute_checksum(const char *data, size_t size) {
uint32_t total = 0;
for (size_t i = 0; i < size; i += sizeof(uint32_t)) {
uint32_t thisone;
std::memcpy(&thisone, &data[i], sizeof(uint32_t));
total += thisone;
}
return total;
}
十分な最適化までを取り除くmemcpyのuint32_t変数全gcc、読みの整数値unaligned、何を最も効率的な方法は、お使いのプラットフォーム、ソース配列の型になります。思いその他の"重大な"コンパイラでコンパイル.このコードが現在よりも大きlitbのではないかとなるとそれ以外の鉱山が容易に機能テンプレートを作ってuint64_t、鉱山としてのネイティブエンディアンらしさではなく狩りちょっとエンディアンです。※
これはもちろん、そうではありません完全にブランドだ。では、その保管に表現sizeof(uint32_t)charに対応した保管を表現したuin32_tのないままです。これは黙示を問いかついては、できる"確信しております。エンディアンされるかどうかは、charは8ビットかuint32_tがすべて使用されていますビットの保管に表現できることで侵入が問題となった。
が私の五セント-様々なことを思い出します。
#include <iostream>
#include <string>
#include <cstring>
uint32_t compute_checksum_memcpy(const char *data, size_t size)
{
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
{
// memcpy may be slow, unneeded allocation
uint32_t dest;
memcpy(&dest,data+i,4);
checksum += dest;
}
return checksum;
}
uint32_t compute_checksum_address_recast(const char *data, size_t size)
{
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
{
//classic old type punning
checksum += *(uint32_t*)(data+i);
}
return checksum;
}
uint32_t compute_checksum_union(const char *data, size_t size)
{
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
{
//Syntax hell
checksum += *((union{const char* c;uint32_t* i;}){.c=data+i}).i;
}
return checksum;
}
// Wrong!
uint32_t compute_checksum_deref(const char *data, size_t size)
{
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
{
checksum += *&data[i];
}
return checksum;
}
// Wrong!
uint32_t compute_checksum_cast(const char *data, size_t size)
{
uint32_t checksum = 0;
for (size_t i = 0; i != size / 4; ++i)
{
checksum += *(data+i);
}
return checksum;
}
int main()
{
const char* data = "ABCDEFGH";
std::cout << compute_checksum_memcpy(data, 8) << " OK\n";
std::cout << compute_checksum_address_recast(data, 8) << " OK\n";
std::cout << compute_checksum_union(data, 8) << " OK\n";
std::cout << compute_checksum_deref(data, 8) << " Fail\n";
std::cout << compute_checksum_cast(data, 8) << " Fail\n";
}
このスレッドが経過していながらがったポストプリ鋳通常このようなことがいえるでしょう:
// safely cast between types without breaking strict aliasing rules
template<typename ReturnType, typename OriginalType>
ReturnType Cast( OriginalType Variable )
{
union
{
OriginalType In;
ReturnType Out;
};
In = Variable;
return Out;
}
// example usage
int i = 0x3f800000;
float f = Cast<float>( i );
願いしますっ!
このような場合は書籍の例するために使用さ reinterpret_cast
, なんでもかんと同じ効果がなく分かりやすさから使用言語の構築のための公式の使用。