テンプレートをいじってみると、C ++では許可されていないと思っていた、配列とそのサイズの定義に関する興味深い現象に遭遇しました。
main()内の配列のサイズを定義するためにグローバル変数を使用しましたが、何らかの理由で機能しました(以下のコードを参照)
1)なぜこれがコンパイルされるのですか?配列サイズにはconstexprのみを使用できると思いました
2)上記が有効であるとすると、文字列のサイズよりも明らかに小さいsz = 8の場合でも、なぜ機能するのかは説明されていません。
3)なぜ私たちはその奇妙な「@」と「?」を取得しているのですか?文字列のさまざまな組み合わせを試しました。たとえば、数字のみ( "123456789")でしたが、表示されませんでした。
助けに感謝します。ありがとう。
これが私のコードです
#include <iostream>
#include <cstring>
using namespace std;
int sz = 8;
int main()
{
const char temp[sz] = "123456abc"; //9 characters + 1 null?
cout << temp << endl;
return 0;
}
出力:
123456ab @
1)なぜこれがコンパイルされるのですか?配列サイズにはconstexprのみを使用できると思いました
質問者は、可変長配列(VLA)が標準C ++ではないということは正しいです。g ++コンパイラには、拡張機能によるVLAのサポートが含まれています。どうすればいいの?コンパイラ開発者は、標準で要求される動作が満たされている限り、必要なものをほとんど追加できます。動作を文書化するのは開発者次第です。
2)上記が有効であるとすると、文字列のサイズよりも明らかに小さいsz = 8の場合でも、なぜ機能するのかは説明されていません。
通常、配列が配列のサイズを超える値で初期化されると、g ++はエラーを発行します。この場合、C ++標準でエラーが必要かどうかを確認するには、ドキュメントで確認する必要があります。エラーが発生するのは良い場所のようですが、エラーが必要かどうかは思い出せません。
この場合、VLA拡張機能には、g ++が配列を過剰に埋めようとして通常吐き出すエラーを排除する副作用があるようです。コンパイラは、一般的な場合、コンパイル時に配列のサイズを認識せず、テストを実行できないため、これは非常に理にかなっています。テストもエラーもありません。
VLAはサポートされていないため、これはC ++標準ではカバーされていません。
VLAを許可するC標準をざっと見ても、この場合のガイダンスは見つかりませんでした。CVLAを初期化するためのルールは非常に単純です。できません。コンパイラは、コンパイル時に配列の大きさがわからないため、初期化できません。文字列リテラルには例外があるかもしれませんが、私はそれを見つけていません。
また、GCCドキュメントで動作の適切な説明を見つけられませんでした。
clangは、C標準の読み取りに基づいて予想されるエラーを生成します:エラー:可変サイズのオブジェクトが初期化されていない可能性があります
補遺:おそらく最初にStack Overflowをチェックして、多くの時間を節約する必要がありました:可変長配列を初期化しています。
3)なぜ私たちはその奇妙な「@」と「?」を取得しているのですか?文字列のさまざまな組み合わせを試しました。たとえば、数字のみ( "123456789")でしたが、表示されませんでした。
起こっているように見えますが、これは標準ではないので、バックアップする引用符はありません。文字列リテラルがVLAのサイズまでVLAにコピーされます。VLAの終わりを過ぎたリテラルの部分は、黙って破棄されます。これにはヌルターミネータが含まれ、終了していないchar
配列を出力するときの動作は定義されていません。
解決:
可能な場合は、標準化された動作に固執します。主要なコンパイラには、非標準コードについて警告するオプションがあります。-pedantic
gccオプションを使用するコンパイラーおよび/permissive-
最近のバージョンのVisualStudioで使用します。標準の外に出ることを余儀なくされた場合、スティッキーまたは文書化されていないビットについては、コンパイラのドキュメントまたは実装者自身に相談してください。
良い答えが得られない場合は、別の方法を探してみてください。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加