3

この関数があると想像してください:

void foo(long l) { /* do something with l */}

これで、呼び出しサイトで次のように呼び出します。

foo(65); // here 65 is of type int

なぜ、(技術的に) 関数の宣言で a を期待していることを指定しlong、接尾辞なしで数値だけを渡すと、Lそれは として扱われるのintですか?

さて、C++ 標準がそう言っているためであることはわかっていますが、これ65が型に昇格されただけでなく、サフィックスをlong忘れて明示的に long にするというばかげたエラーを回避する技術的な理由は何ですか?L

C++標準でこれを見つけました:

4.7 積分変換 [conv.integral]

5 インテグラル プロモーションとして許可されているコンバージョンは、インテグラル コンバージョンのセットから除外されます。

縮小変換が暗黙的に行われていないことは考えられますが、ここでは宛先の型がソースの型よりも明らかに広くなっています。

編集

この質問は、サフィックス を指定しなかった場合に奇妙な動作があった、以前に見た質問に基づいています。Exampleですが、おそらくそれは C++ よりも C のことでしょうか?!!L

4

5 に答える 5

4

C++ では、オブジェクトと値には型があり、使用方法に依存しません。それらを使用するときに、別のタイプが必要な場合は、適切に変換されます。

リンクされた質問の問題は、varargs がタイプセーフではないことです。正しい型を渡し、それらが何であるかをデコードすることを前提としています。呼び出し元を処理している間、コンパイラーは、呼び出し先が各引数をどのようにデコードするかを知らないため、それらを変換できない可能性があります。事実上、varargs は avoid*に変換して別の型に変換し直すのと同じくらいタイプセーフです。正しい場合はプッシュしたものを取得し、間違っている場合はごみを取得します。

また、この特定のケースでは、インライン化によりコンパイラは十分な情報を持っていますが、これは一般的なファミリーの if エラーの小さなケースにすぎないことに注意してください。関数のファミリを考えてみましょう。printf最初の引数の内容に応じて、各引数が異なる型として処理されます。このケースを言語レベルで修正しようとすると、矛盾が生じます。場合によっては、コンパイラが正しいことを実行するか間違ったものを実行し、どちらを期待するかがユーザーには明確ではなくなります。リファクタリング中に関数定義が移動されてインライン化できなくなった場合、または関数のロジックが変更され、引数が以前のパラメーターに基づいて何らかの型として処理された場合、今日は正しく、明日は間違ったものになります。

于 2013-03-18T16:29:53.907 に答える
1

このインスタンスの関数は、longではなくを受け取りますint。情報を失うことなく可能であれば、コンパイラは任意の引数を必要なパラメーターの型に自動的に変換します (こちらを参照)。これが、関数プロトタイプが重要な主な理由の 1 つです。

のような式の場合と本質的に同じ(1L + 1)です。整数は正しい型ではないため、計算を実行するために1暗黙的に a に変換され、結果は a になります。longlong

この関数呼び出しを渡す場合65L、型変換は必要ありませんが、実質的な違い65Lはありません。どちらの方法でも使用されます。

C++ ではありませんが、これは C99 標準の関連部分であり、var args の注記についても説明しています。

呼び出された関数を示す式がプロトタイプを含まない型を持つ場合、引数は対応するパラメーターの型に代入のように暗黙的に変換され、各パラメーターの型は宣言された型の非修飾バージョンになります。タイプ。関数プロトタイプ宣言子の省略記号表記により、最後に宣言されたパラメーターの後で引数の型変換が停止します。デフォルトの引数昇格は、末尾の引数に対して実行されます。

于 2013-03-18T16:23:58.457 に答える
1

なぜ、(技術的に) long を期待していることを関数の宣言で指定し、L接尾辞なしで数値だけを渡すと、それは として扱われるのintですか?

リテラルの型は、それが使用されるコンテキストではなく、リテラルの形式によってのみ指定されるためです。整数intの場合は、その型に対して値が大きすぎる場合や、別の型を指定するために接尾辞が使用されている場合を除きます。

longさて、C++ 標準がそう言っているためであることはわかっLていますが、この 65 が単に型に昇格されないという技術的な理由は何longですか?

long関数は type の引数を取るように宣言されているため、その型を明示的に指定するかどうかにかかわらず、値は に昇格する必要がありますlong。そうでない場合は、失敗するコードの例を挙げて、それがどのように失敗するかを説明できますか?

UPDATE:あなたが与える例...は、型付きlong引数ではなく、型なし省略記号()引数をとる関数にリテラルを渡します。その場合、関数の呼び出し元は期待される型がわからず、デフォルトの引数プロモーションのみが適用されます。具体的には、タイプの値は、省略記号引数を介して渡されintた場合に残ります。int

于 2013-03-18T16:27:04.100 に答える
0

C 標準には次のように記載されています。

「整数定数の型は、その値を表すことができる対応するリストの最初のものです。」

C89 では、このリストは次のとおりです。

int, long int, unsigned long int

C99 はそのリストを拡張して、以下を含めます。

long long int, unsigned long long int

そのため、コードをコンパイルすると、リテラル 65 は int 型に収まるため、型はそれに応じて int になります。関数が呼び出されると、int は long に昇格されます。

たとえば、sizeof(int) == 2 でリテラルが 64000 のような場合、値の型は long になります (sizeof(long) > sizeof(int) と仮定)。

サフィックスは、デフォルトの動作を上書きし、指定されたリテラル値を強制的に特定の型にするために使用されます。これは、整数の昇格にコストがかかる場合 (たとえば、タイトなループ内の方程式の一部として) に特に役立ちます。

于 2013-03-18T16:24:03.353 に答える
0

低レベルのアプリケーションでは、特に整数型の場合、型は本当に重要であるため、型には標準的な意味が必要です。低レベルの演算子 (bitshift、add、ect など) は、入力の型に依存してオーバーフローの場所を決定します。((65 << 2) は整数では 260 (0x104) ですが、単一の文字では 4! (0x004) です)。この動作が必要な場合もあれば、そうでない場合もあります。プログラマーとして、コンパイラーが何をしようとしているのかを常に知ることができる必要があります。したがって、人間が定数の整数型を明示的に宣言するように設計上の決定が行われ、最も一般的に使用される型である整数として「装飾なし」が使用されました。

コンパイラは、関数に渡される有効な値が長いように、コンパイル時に定数式を自動的に「キャスト」しますが、キャストするまでは、この理由で int と見なされます。

于 2013-03-18T16:28:46.050 に答える