問題タブ [strict-aliasing]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - long double ビット表現へのアクセス
TLDR; 次のコードは、未定義 (または未指定) の動作を呼び出しますか?
私の x86-64 マシンでは、出力はコンパイラに渡された特定の最適化フラグ (gcc-4.8.0、-O0 と -O1) によって異なります。
-O0 を使用すると、
-O1を使用している間、私は得る
最後から 2 行目に余分な 1 があることに注意してください。また、memset の後に印刷命令のコメントを外すと、その 1 が消えます。これは、次の 2 つの事実に依存しているようです。
- long double はパディングされます。つまり、sizeof(long double) = 16 ですが、10 バイトしか使用されません。
- memset への呼び出しが最適化される可能性があります
- long double のパディング ビットは予告なしに変更される可能性があります。つまり、value1 と value2 の浮動小数点演算は、パディング ビットをスクランブルするように見えます。
私はコンパイルして-std=c99 -Wall -Wextra -Wpedantic
いて警告が出ないので、これが厳密なエイリアシング違反のケースであるかどうかはわかりません (しかし、そうかもしれません)。通過-fno-strict-aliasing
しても何も変わりません。
コンテキストは、ここで説明されている HDF5 ライブラリで見つかったバグです。HDF5 は、浮動小数点型のネイティブ ビット表現を把握するために多少の調整を行いますが、パディング ビットがゼロのままでないと混乱します。
そう:
- これは未定義の動作ですか?
- これは厳密なエイリアシング違反ですか?
ありがとう。
編集: これは printme のコードです。あまり注意を払わずにどこかからカット&ペーストしたことを認めます。ここに問題がある場合は、ズボンを下ろしたままテーブルを回ります。
c - dlsym() の戻り値を関数型に割り当てる方法は?
私の問題は次のとおりです。
次のような関数ポインタを含む構造があります。
今、まさにそのタイプの関数ポインタをそれに割り当てたいと思います。しかし悲しいことに、次のようなものではなくa をdlsym()
返していますvoid *
function_poitner_type
だから私の最初の試み:
警告で終了しました:
警告: ISO C では、関数ポインタと 'void *' の間の割り当てが禁止されています
わかりました、それは私を混乱させました... gccは私にそれほど厳しいことを話したことはありませんでした。しかし、ちょっとトリッキーにしましょう。標準準拠を維持するためのバックドアがおそらくあると思いました。だから私はこれを試しました:
うーん……たしかに……
警告: 型打ちされたポインターを逆参照すると、厳密なエイリアシング規則が破られます
内部で何が起こっているのかわからないので、関数をエイリアスする実数が返されるか、まったく別の何かdlsym()
が返されるため、壊れるかどうかわかりません。void *
したがって、この関数ポインターを使用すると、厳密なエイリアスルールが破られるのか、それとも破れないのかわかりません。
とにかく、私の会社では、 compilerflag を使用することは法律-fstrict-aliasing
です。したがって、これは、適合したとしても、私にとって可能な解決策ではありません。
というわけで続けてみました。
私の次のアイデアは、 のchar *
バージョンdlsym()
を memcopy に解析するにはどうすればよいかということでした。
結果:
私が今得ている警告は、かなり具体的です:
警告: ISO C は、関数ポインタと void * の間で 'memcpy' の引数 1 を渡すことを禁止しています
だから私の次のアイデアは、「バイトに戻ろう」というものでした。(しかし、徐々にアイデアが不足しています...)
だから私はした:
これは静かな別の警告で終わりました:
警告: ISO C では、関数ポインタからオブジェクト ポインタ型への変換が禁止されています
最後に、私の最も奇妙な試みは次のとおりです。
そしてここでも問題は、それが関数ポインターであるため、offsetoff
2番目のパラメーターに変換できないことです。void *
私は立ち往生していて、さらに先に進む方法がわかりません。誰かが解決策を見つけるのを手伝ってくれますか?
clangではなくgcc 4.2を使用すると、これらの警告が表示されます。
対象となる C バージョンは、-std=c99
回避することです。-std=POSIX
-std=gnu99
しかし、この gcc 警告は私には時代遅れに聞こえません。私は現在 FreeBSD に取り組んでいますが、これを解決する方法がまったくわかりません。
c - バッファを構造体として解釈するための、移植可能な正しい方法
私の問題のコンテキストは、ネットワーク プログラミングにあります。2 つのプログラム間でネットワーク経由でメッセージを送信したいとします。簡単にするために、メッセージが次のように表示され、バイト順は問題ではないとします。これらのメッセージを C 構造体として定義する、正しく、移植可能で、効率的な方法を見つけたいと考えています。これには、明示的なキャスト、共用体によるキャスト、コピー、およびマーシャリングという 4 つのアプローチがあります。
明示的なキャスト:
私の理解ではsend_message
、バイト/文字ポインターは任意の型に別名を付ける可能性があるため、別名規則に違反していません。ただし、その逆は当てはまらないため、receive_message
エイリアシング ルールに違反し、未定義の動作になります。
ユニオンによるキャスト:
ただし、これは、ユニオンには常にそのメンバーの1つしか含まれないという考えに違反しているようです。さらに、ソース バッファーがワード/ハーフワード境界で整列されていない場合、整列の問題が発生する可能性があるようです。
コピー中:
これは正しい結果を生成することが保証されているようですが、もちろんデータをコピーする必要はありません。
マーシャリング
まだコピーする必要がありますが、構造体の表現から分離されました。しかし今では、各メンバーの位置とサイズを明示する必要があり、エンディアンはより明白な問題です。
関連情報:
標準に違反することなく、構造体へのポインタを使用して配列をエイリアシングする
厳密なポインターエイリアシングに対してchar *が安全なのはいつですか?
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
実際の例
この状況が他の場所でどのように処理されるかを確認するために、ネットワーク コードの例を探していました。軽量 ipには、いくつかの同様のケースがあります。udp.cファイルには、次のコードがあります。
ここstruct udp_hdr
で、 は udp ヘッダーのパック表現でありp->payload
、タイプはvoid *
です。私の理解とこの答えに進むと、これは間違いなく[edit-not] strict-aliasing を破っているため、未定義の動作をしています。
c++ - aligned_storage を使用する際の厳密なエイリアシング エラーを回避する方法
std::aligned_storage
バリアント テンプレートのバッキング ストレージとして使用しています。問題は、-O2
gcc で有効にすると、「タイプがパニングされたポインターを逆参照すると厳密なエイリアシングが壊れる」という警告が表示され始めることです。
実際のテンプレートはもっと複雑です (実行時に型がチェックされます) が、警告を生成するための最小限の例は次のとおりです。
これと本質的に同じことをしていると確信しboost::variant
ていますが、この問題を回避する方法を見つけることができないようです。
私の質問は次のとおりです。
- このように使用
aligned_storage
すると厳密なエイリアスに違反する場合、どのように使用すればよいですか? get()
関数に他のポインターベースの操作がない場合 、厳密なエイリアシングの問題は実際にありますか?get()
がインライン化されている場合はどうですか?- どう
get() = 4; get() = 3.2
ですか?タイプが異なるためにint
、そのシーケンスを並べ替えることができますか?float
c - `restrict` キーワードによって暗示される厳密なエイリアスのレベルは?
私は次の構造を持っています:
次のように使用します。
私の質問は次のとおりです。厳密なエイリアシングを削除するとd
、そのメンバーにも影響しrestrict
ますか、それとも個別に使用する必要がありますか? 言い換えれば、構造体に含まれるすべてのポインターが同じ扱いを受けるrestrict
ことを意味しますか?
編集:エイリアシングのレベルによって、つまり、構造体へのポインターがrestrict
ed になると、それに含まれる他のポインターも制限されます (私の例の場合のように)。
c++ - (double *) から (double **) へのキャストは許可されていますか?
「互換性のないポインター型によるエイリアシングは未定義の動作です」と言われている議論に従ったためです(たとえばdouble d; int *p = (int *)&d;
、次の質問:
(double *)
to(double **)
をキャストすることは許可されてdouble *d1; double **d2 = &d2
いd2[0][y]
ますかd1[y]
?
互換性のないポインター型による正確なエイリアシングではないことはわかっていますが、よくわかりません。背景は、2 次元配列 (= 画像) を操作する関数が必要ですが、画像の行または列のみを渡すことができるようにしたいということです。
c++ - 配置によって返されるポインターを使用しない場合の C++ の厳密なエイリアシング new
これにより、未定義の動作が発生する可能性がありますか?
char
厳密なエイリアスに関する特別なルールがあります。char
代わり に使用するuint8_t
と、まだ未定義の動作ですか? 他に何が変わる?
メンバー DeadMG が指摘したように、reinterpret_cast
実装に依存します。(int32_t*)storage
代わりにC スタイルのキャストを使用すると、何が変わるでしょうか?
c++ - 「this」ポインターを別の型にキャストしても、厳密なエイリアシングに違反しませんか?
したがって、次のようなことをすると:
注:「m_data」と「this」は同じ場所を指す必要があります...
gcc 4.8.1