0

値に型がないというトピック、記事、およびSOの回答を読みまし#defineた。型は値自体のプロパティではなく、コンテナー変数のプロパティであると考えて、この概念について決心しました。

const char cVALUE = 100;    // 'cVALUE' is char with value 100, wich type is '100'?
const short sVALUE = 100;   // 'sVALUE' is short with value 100, wich type is '100'?
const int iVALUE = 100;     // 'iVALUE' is int with value 100, wich type is '100'?
#define VALUE 100           // wich type is 'VALUE'?

しかし、値の接尾辞はどうですか?

#define VALUE_L   100l   // 'VALUE_L' is long?
#define VALUE_UL  100ul  // 'VALUE_UL' is unsigned long?
#define VALUE_LL  100ll  // 'VALUE_LL' is long long?
#define VALUE_ULL 100ull // 'VALUE_ULL' is unsigned long long?

上記のコードでは、型が値に関連付けられているように見えるため、以前に読んだものとは対照的に、この生の値はすべて型付きの値です。しかし、もっとあります!テキスト リテラルには修飾子もあります。次に例を示します。

#define TEXT "Text" // '"Text"' is an array of some kind of chars.

上記のテキスト値に#defineはタイプがあります (文字タイプ、MSVC を使用している場合、プロジェクト設定を変更すると文字タイプが異なる可能性があると思います -> Character set、別の IDE で可能かどうかはわかりません)。 cualifier であり、constそれが RValue ではなく LValue である場合、数値リテラルとテキスト リテラルの間のこのすべての動作の違いが気になります。

したがって、文字タイプがcharであるとすると、リテラルのタイプ"Text"const char *const char * constまたはconst char[5]? または、少なくとも、コンテキストで正しい型が推定される前に型がまったくありませんか?

また、C++11 標準では、文字セットを設定するいくつかのプレフィックスを使用して、テキスト リテラルに型を指定することもできます。

#define TEXT   L"Text"  // wide string with char type wchar_t
#define TEXTu8 u8"Text" // UTF-8 string with char type char
#define TEXTu  u"Text"  // UTF-16 string with char type char16_t
#define TEXTU  U"Text"  // UTF-32 string with char type char32_t

これらすべてのことを考えた後、私はかなり混乱しているので、アドバイスを求めています。

  • リテラル値 (および#defines) には型がなく、リテラルで型を指定できるという一般的な知識があるのはなぜですか? つまり、値リテラルに型がないことをアサートするのは false ですか?
  • 接尾辞も小数部もない値リテラル( など100) は、常に int 型と見なすことができますか?
  • 接頭辞を考慮しても、テキストリテラルの型と修飾子はどれですか?
4

7 に答える 7

4

C および C++ では、プリプロセッサとコンパイラは 2 つの別個のエンティティです。

#defines およびその他のプリプロセッサ ディレクティブを処理するプリプロセッサには、型システムがありません。文字列を操作します。そして、これらの文字が表す値は、コンパイラ自体に任されています。

検討

#define Y x[

文字列は C では意味がありませんが、これは正当なプリプロセッサ ディレクティブx[です。それでも、次のように使用できます。

char Y 10];

の配列を宣言しxますchar

実際、C プリプロセッサは、C 以外の言語のソース ファイルで使用できます。たとえば、FORTRAN ソースでよく使用されます。FORTRAN には標準のプリプロセッサがないためです。

于 2013-01-22T16:14:36.320 に答える
2

まず、あなたの質問:

値リテラルに型がないことをアサートするのは偽ですか?

はい。

接尾辞や小数 (100 など) のない値リテラルは、常に int 型と見なすことができますか?

デフォルトでは、 type を取得すると思いますint

接頭辞を考慮しても、テキストリテラルの型と修飾子はどれですか?

私の記憶が正しければ、デフォルトのタイプはchar []です。

第二に、いくつかのコンテキスト:

値リテラルには型があります。明示的に指定されていないだけで、すべての型をそのように指定できるわけではありません。

定数を宣言することで、型を明示的に指定し、コンパイラにより多くの情報を提供できます。

次のことを考慮してください。

#define VALUE1 102

値が int リテラルであることがわかります。

const を宣言すると、次のように言えます。

static const int VALUE1 = 102;
static const float VALUE1  = 102;
static const double VALUE1 = 102;
static const unsigned int VALUE1 = 102;

正しい/より良い方法(正しいとは、定数defineを使用するための相対的な用語です) は次のようになります。define

#define VALUE1 (int(102))
#define VALUE1 (float(102))
// etc ...

この時点で、定数を追加することをお勧めします。

于 2013-01-22T16:20:09.640 に答える
2

リテラル値 (および #defines) には型がなく、リテラルで型を指定できるという一般的な知識があるのはなぜですか? つまり、値リテラルに型がないことをアサートするのは false ですか?

そうではありません。C++11 標準のセクション 2.14 で指定されているように、リテラルにはすべて型があります。プリプロセッサ マクロは、リテラルが解釈される前に置き換えられます。

接尾辞と小数 (100 など) のない値リテラルは、常に int 型と見なすことができますか?

いいえ; 10 進リテラルは の最初のintlong intまたはlong long int値を表すことができます。必要に応じて、8 進数または 16 進数のリテラルも符号なしにすることができます。2011年以前long longは標準型ではないため考慮していませんでした。

で表現できるほど小さいので、型100があります。intint

接頭辞を考慮しても、テキストリテラルの型と修飾子はどれですか?

プレフィックスがない場合はconst char、すべての文字とゼロ ターミネータを保持するのに十分な大きさの の配列になります。type"Text"も同様char const[5]です。

プレフィックスを使用すると、文字タイプが質問で指定したタイプに変更されます。配列のサイズは、ターミネータを含むすべての文字に対してまだ十分な大きさです。

于 2013-01-22T16:28:05.017 に答える
2

プリプロセッサには型がないという点で、それらは正しいです。あなたの例

#define VALUE_L   100l

VALUE_Lこれはtype を持つという意味ではありませんlong。プリプロセッサを使用して、そのテキストを文字列リテラルの途中に挿入できます。たとえば、this .

マクロにはタイプがありません。プリプロセッサは、コンパイラが型を持っていると解釈できるトークンを作成できますが、これは正接であり、そのようなことを行う必要はありません。

また、L""リテラルは C++03 およびwchar_t. リテラル""は typeconst char[1]を持ち、左辺値です。それらが左辺値である理由は、伝統的に、それらは で指され、const char*そのポインターは左辺値を指さなければならないためです。

于 2013-01-22T16:24:05.360 に答える
1

#defineプリプロセッサへの指示であり、コピー アンド ペースト スタイルの置換を行うだけです。プリプロセッサは、コードの意味について何も知らず、気にもかけず、型の概念もありません。

前処理の後、コンパイラは式、ステートメント、型などを処理します。すべての式 (オーバーロードされた関数の名前またはアドレスでない限り) には、コードのコンテキストではなく、その式のみに依存する型があります。

(C++11 の波括弧初期化リストには型がなく、技術的には式ではありませんが、多くの同じコンテキストで使用できます。)

プリプロセッサ#define VALUE 100にとっては意味がありますが、その時点では型の考え方は適用されません。しかし、 after を正しく使用するほとんどの場合、VALUEそれを式として使用し、それらの式はすべて type を持ちintます。

はい、数字のサフィックスと文字列のプレフィックスは、リテラル式の型に影響を与えます。のタイプは100ですintが、 のタイプは100ULですunsigned long

リテラル"Text"には常に typeがありますconst char [5]が、正確な意味と表現はcharコンパイラによって異なります。ほとんどのコンテキストでは、そのリテラルは、暗黙的な配列からポインターへのconst char*型への変換を使用して即座に減衰します。(また、 が発明される前の古い C コードとの下位互換性のためにconst、C++ ではchar*文字列リテラルから変数を初期化できますが、それを行わない方がよいでしょう。)

同様に、リテラルL"Text"には typeconst wchar_t [5]などがあります。

于 2013-01-22T18:15:37.107 に答える
0

A#defineは、すべてのインスタンスを定義に置き換えるようにプリコンパイラーに指示するため、型は変数内で明示的ではありませんが、それが表すリテラル値を調べることで判別できます。

  • 整数リテラルはint修飾子がない場合、またはlong436234636Lのように作成することができます。
  • 文字列リテラルは、質問のように修飾子が追加されていない限り、通常の文字列です。
于 2013-01-22T16:07:21.473 に答える
0

プリプロセッサがテキスト#define VALUE 100を見ると、文字列 [またはそのようなもの] と「置換」を 100 として格納しますVALUE。プリプロセッサが後で を見つけるVALUEと、それを に置き換えます100。そのため、VALUEタイプはありません。100Cのテキストには型があります。それは です。これintは、言語の規則がそう言っているからです。

プリプロセッサの置換は、適切なコンパイルの前に行われることに注意してください。そのため、プリプロセッサの置換は、マクロなしでは困難な (または不可能な) あらゆる種類の「奇妙な」ことを行うことができます。

繰り返しますが、プリプロセッサは単純に and に置き換えられTEXT"Text"その時点では型がありません。型は適切なコンパイラにのみ存在します。あなたが持っている場合:

#define TEXT "Text"

void myfun(int x)
{
   ... 
}

... 
myfun(TEXT);

プリプロセッサは生成します

...
myfun("Text");

コードの適切なコンパイルに到達した場合にのみ、コンパイラは「うーん、これはテキスト文字列です。期待どおりの整数ではありません」と判断し、何らかのエラーを表示します。

の「タイプ」に関しては"Text"、正確なコンテキストに依存します。ほとんどの場合、 として扱うのが安全ですconst char *が、状況によっては と見なすこともできますchar [5]

于 2013-01-22T16:18:08.807 に答える