タグ付けされた質問 「language-lawyer」

プログラミング言語と環境の正式または信頼できる仕様の複雑さについての質問。

7
値0の代わりにNULLを使用できますか?
NULLの値の代わりにポインタを使用でき0ますか? それとも、そのことについて何か問題がありますか? たとえば、 int i = NULL; の代わりとして: int i = 0; 実験として、次のコードをコンパイルしました。 #include <stdio.h> int main(void) { int i = NULL; printf("%d",i); return 0; } 出力: 0 確かにそれは私にこの警告を与えます、それ自体は完全に正しいです: warning: initialization makes integer from pointer without a cast [-Wint-conversion] しかし、結果は同じです。 これで「未定義の動作」にぶつかりますか? NULLこのように利用することは許されますか? NULL算術式の数値として使用することに問題はありますか? そして、この場合のC ++の結果と動作は何ですか? 私はの答え読み持っている「\ 0」、NULLの違いは何をして0との違いは何かについてNULL、\0そして0それが正しい使用にも非常に許容され、場合、ですが、私はそこからの簡潔な情報を取得していないNULLとして、代入やその他の算術演算で操作する値。


3
std :: vector(ab)は自動ストレージを使用します
次のスニペットを考えてみましょう: #include <array> int main() { using huge_type = std::array<char, 20*1024*1024>; huge_type t; } 通常、デフォルトのスタックサイズは通常20MB未満であるため、ほとんどのプラットフォームでクラッシュします。 次のコードを考えてみましょう: #include <array> #include <vector> int main() { using huge_type = std::array<char, 20*1024*1024>; std::vector<huge_type> v(1); } 意外にもクラッシュします!トレースバック(最近のlibstdc ++バージョンの1つを使用)はinclude/bits/stl_uninitialized.hファイルにつながり、ここに次の行が表示されます。 typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; std::fill(__first, __last, _ValueType()); サイズ変更vectorコンストラクターは、要素をデフォルトで初期化する必要があります。これが実装方法です。明らかに、_ValueType()一時的にスタックがクラッシュします。 問題は、それが適合実装であるかどうかです。はいの場合、それは実際には巨大な型のベクトルの使用がかなり制限されていることを意味しますね?

2
コピーコンストラクターでのC ++名前空間の競合
私は次のコードを持っています: namespace A { struct Foo { int a; }; } struct Foo { int b; }; struct Bar : public A::Foo { Bar(Foo foo) { c = foo.b; } int c; }; A :: Fooにはbという名前のメンバーがないため、C ++コンパイラーは「c = foo.b」で不平を言います。:: FooでBarパラメータのタイプを変更すると、機能します。 私の質問は、この動作の背後にある合理的なものは何ですか(私はそれが継承によってBarがA名前空間に入るようにするという事実に関係していると思いますが、この理論をサポートするドキュメントを見つけることができません。

3
C ++ decltypeと括弧-なぜですか?
主題は以前に議論されました が、これは重複ではありません。 decltype(a)との違いについて質問された場合decltype((a))、通常の答えは- aは変数で(a)あり、は式です。私はこの答えに満足できないと思います。 まず、a表現もです。一次式のオプションには、特に- (式) id式 さらに重要なことに、decltypeの表現では、括弧が非常に明示的に考慮されます。 For an expression e, the type denoted by decltype(e) is defined as follows: (1.1) if e is an unparenthesized id-expression naming a structured binding, ... (1.2) otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter, ... (1.3) otherwise, if e …

6
2バイトを符号付き16ビット整数に変換する正しい方法は何ですか?
では、この答え、zwolはこの主張をしました。 2バイトのデータを外部ソースから16ビットの符号付き整数に変換する正しい方法は、次のようなヘルパー関数を使用することです。 #include <stdint.h> int16_t be16_to_cpu_signed(const uint8_t data[static 2]) { uint32_t val = (((uint32_t)data[0]) << 8) | (((uint32_t)data[1]) << 0); return ((int32_t) val) - 0x10000u; } int16_t le16_to_cpu_signed(const uint8_t data[static 2]) { uint32_t val = (((uint32_t)data[0]) << 0) | (((uint32_t)data[1]) << 8); return ((int32_t) val) - 0x10000u; } 上記の関数のどちらが適切かは、配列にリトルエンディアン表現またはビッグエンディアン表現が含まれるかどうかによって異なります。エンディアンネスはここでの問題ではありません、なぜzwolがに変換さ0x10000uれたuint32_t値から減算するのか疑問に思っていint32_tます。 なぜこれが正しい方法ですか? …

2
なぜCのBNF文法は、空のinit-declaratorのシーケンスでの宣言を許可するのですか?
CのBNF文法を調べたとき、宣言のプロダクションルールが次のようになっているのは奇妙だと思いました(https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%によると) 20C%20in%20Backus-Naur%20form.htm): <declaration> ::= {<declaration-specifier>}+ {<init-declarator>}* ; なぜ*量指定子(0回以上のオカレンス)を使用するのinit-declaratorですか?これにより、int;またはなどのステートメントvoid;は、意味的に無効であっても、構文的に有効になります。プロダクションルールでは+なく、数量詞(1つ以上のオカレンス)を使用しただけではありません*か? 単純なプログラムをコンパイルして、コンパイラーが何を出力するかを確認しましたが、コンパイラーが行うのは警告を出すことだけです。 入力: int main(void) { int; } 出力: test.c: In function ‘main’: test.c:2:5: warning: useless type name in empty declaration int; ^~~

2
std :: hashが確定的であることが保証されていないのはなぜですか?
以降、N4140(C ++ 14 Standard)を使用します。 §17.6.3.4ハッシュ要件によると、 返される値k は、プログラム期間中の引数にのみ依存します。 [注:したがってh(k)、の同じ値を持つ 式のすべての評価は、プログラムの特定の実行に対してk同じ結果になります。—エンドノート] および§20.9.12クラステンプレートハッシュは言う ... インスタンス化hash<Key>は: (1.1)—ハッシュ要件を満たす(17.6.3.4)... (1.2)— ... これは、プログラムを再起動した場合value(つまりhash<decltype(value)>(value))のハッシュ値が別の値になる場合があることを意味します。 しかし、なぜ?この制限は、C ++ 11の標準ではなく、C ++ 14、C ++ 17、およびC ++ 20の標準にありました。ユーザー(STL開発者ではない)として、std::hash決定論的である場合は非常に便利です。確定的ハッシュ関数の実装に数学的な困難はありますか?しかし、私たちが日常的に使用しているハッシュ関数(たとえば、非推奨md5sumまたはより安全sha256)はすべて確定的です。効率の問題はありますか?

1
クラスが独自のプライベート静的constexprメソッドにアクセスできない-Clangバグ?
このコードはClang(6、7、8、9、trunk)ではコンパイルされませんが、GCC(7.1、8.1、9.1)では問題なくコンパイルされます。 template<class T> struct TypeHolder { using type = T; }; template<int i> class Outer { private: template<class T> static constexpr auto compute_type() { if constexpr (i == 42) { return TypeHolder<bool>{}; } else { return TypeHolder<T>{}; } } public: template<class T> using TheType = typename decltype(Outer<i>::compute_type<T>())::type; }; int main() …

2
2次元配列のエイリアスを作成するときのstrlenの予期しない最適化
これが私のコードです: #include <string.h> #include <stdio.h> typedef char BUF[8]; typedef struct { BUF b[23]; } S; S s; int main() { int n; memcpy(&s, "1234567812345678", 17); n = strlen((char *)&s.b) / sizeof(BUF); printf("%d\n", n); n = strlen((char *)&s) / sizeof(BUF); printf("%d\n", n); } gcc 8.3.0または8.2.1を最適化レベル以外で使用すると-O0、0 2期待していたとおりに出力されます2 2。コンパイラは、strlenがに制限されb[0]ているため、除算される値と同じかそれ以上になることはないと判断しました。 これは私のコードのバグですか、コンパイラのバグですか? これは明確に規格に明記されていませんが、ポインターの来歴の主流の解釈は、どのオブジェクトXでも、コード(char *)&Xは全体を反復できるポインターを生成するべきだと思いましたX-この概念はXたまたま持っていても成り立つはずです内部構造としてのサブ配列。 (ボーナス質問、この特定の最適化をオフにするgccフラグはありますか?)

3
変換演算子のこのオーバーロードが選択されるのはなぜですか?
次のコードを検討してください。 struct any { template <typename T> operator T &&() const; template <typename T> operator T &() const; }; int main() { int a = any{}; } ここで、2番目の変換演算子は、過負荷の解決によって選択されます。どうして? 私の理解する限り、2つの演算子はそれぞれoperator int &&() constとに推定されoperator int &() constます。どちらも実行可能な関数のセットに含まれています。[over.match.best]を読んでも、後者が優れている理由を理解するのに役立ちませんでした。 なぜ後者は前者よりも機能が優れているのですか?

3
const参照によってデフォルトの引数の値を返すことは問題ありませんか?
以下の例のようにconst参照によってデフォルトの引数の値を返すことは問題ありませんか? https://coliru.stacked-crooked.com/a/ff76e060a007723b #include <string> const std::string& foo(const std::string& s = std::string("")) { return s; } int main() { const std::string& s1 = foo(); std::string s2 = foo(); const std::string& s3 = foo("s"); std::string s4 = foo("s"); }

1
Cでのオブジェクトのオーバーラップのセマンティクスは何ですか?
次の構造体について考えてみましょう。 struct s { int a, b; }; 典型的には1、この構造体は、サイズ8と位置合わせ4を有するであろう。 2つのstruct sオブジェクトを作成し(より正確には、2つのオブジェクトを割り当てられたストレージに書き込みます)、2番目のオブジェクトが最初のオブジェクトと重なる場合はどうなりますか? char *storage = malloc(3 * sizeof(struct s)); struct s *o1 = (struct s *)storage; // offset 0 struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4 // now, o2 points half way into o1 *o1 …

3
コンパイラーはローカルvolatileを定数フォールドできますか?
この単純なコードを考えてみましょう: void g(); void foo() { volatile bool x = false; if (x) g(); } https://godbolt.org/z/I2kBY7 への潜在的な呼び出しgccもclang最適化もされていないことがわかりgます。これが私の理解で正しいです:抽象マシンは、と仮定することでvolatile一定の折りので変数は、(例えば、ハードウェア・マッピングされたことに起因する)いつでも変更される可能性falseに初期化をifチェックは間違っているだろう。 しかし、MSVCはへの呼び出しをg完全に排除します(volatileただし、読み取りと書き込みを維持します!)。これは標準に準拠した動作ですか? 背景:デバッグ出力をオンザフライでオン/オフできるようにするために、この種のコンストラクトを時々使用します:コンパイラは常にメモリから値を読み取る必要があるため、デバッグ中に変数/メモリを変更すると、それに応じて制御フローが変更されます。MSVC出力は値を再読み取りしますが、それを無視します(たぶん、定数の折りたたみやデッドコードの除去のため)、これはもちろん、ここでの私の意図を無効にします。 編集: 読み取りと書き込みの排除については、volatileここで説明します。コンパイラーがローカルの揮発性変数を最適化することを許可されていますか?(ネイサンに感謝!)標準は、これらの読み取りと書き込みが発生する必要があることを十分に明確に考えています。しかし、その議論は、コンパイラーがそれらの読み取りの結果を当然のこととして受け取り、それに基づいて最適化することが合法かどうかをカバーしていません。私はこれが標準では不十分/不特定であると思いますが、誰かが私を間違っていると証明したら私は幸せです。 もちろんx、問題を回避するために非ローカル変数を作成することもできます。この質問は、好奇心から外れています。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.