#include <stdio.h>
#include <string.h>
int main(void)
{
char ch='a';
printf("sizeof(ch) = %d\n", sizeof(ch));
printf("sizeof('a') = %d\n", sizeof('a'));
printf("sizeof('a'+'b'+'C') = %d\n", sizeof('a'+'b'+'C'));
printf("sizeof(\"a\") = %d\n", sizeof("a"));
}
このプログラムは、sizeof
を使用してサイズを計算します。 'a'
のサイズがch
(ここでch='a'
)のサイズと異なるのはなぜですか?
sizeof(ch) = 1
sizeof('a') = 4
sizeof('a'+'b'+'C') = 4
sizeof("a") = 2
TL; DR-sizeof
は、オペランドのtypeで機能します。
sizeof(ch)
== sizeof (char)
-----------------------------------(1)sizeof('a')
== sizeof(int)
--------------------(2)sizeof ('a'+ 'b' + 'c')
== sizeof(int)
---(3)sizeof ("a")
== sizeof (char [2])
----------(4)各ケースを見てみましょう。
ch
はchar
型であると定義されているため、非常に簡単です。
Cでは、文字定数は整数型であるため、sizeof('a')
はsizeof (int)
と同じです。
C11
を引用
整数文字定数のタイプは
int
です。 [...]
C++では、文字literalの型はchar
です。
sizeof
はコンパイル時の演算子であるため(オペランドがVLAの場合を除く)、式のタイプが使用されます。前述のとおり、すべての整数文字定数はint
型であるため、int
+ int
+ int
はint
を生成します。したがって、オペランドのタイプはint
として扱われます。
"a"
は、2つのchar
s、'a'
および0
(null-terminator)(noの配列です。配列型の最初の要素へのポインタ)、したがって、サイズは2つのchar
要素を持つ配列のサイズと同じです。
最後に、sizeof
はsize_t
型の結果を生成するため、%zu
形式指定子を使用して結果を出力する必要があります。
Cでは、_'a'
_はint
型のconstantです。 not a char
です。したがって、sizeof('a')
はsizeof(int)
と同じになります。
sizeof(ch)
はsizeof(char)
と同じです。 (C標準では、すべての英数字定数(および他のいくつか)が_'a'
_の形式でchar
に収まることが保証されているため、_char ch='a';
_は常に明確に定義されています。)
C++では、_'a'
_はchar
型のliteralであることに注意してください。 CとC++のさらに別の違い。
Cでは、sizeof("a")
はsizeof(char[2])
です。これは2です。sizeof
は、配列型のdecayを引き起こしません。ポインター。
C++では、sizeof("a")
はsizeof(const char[2])
です。これは2です。sizeof
は、配列型のdecayを引き起こしません。ポインター。
両方の言語で、'a'+'b'+'C'
_は、C++では整数型の暗黙的な昇格のため、int
型です。
まず、sizeof
の結果は_size_t
_型であり、_%zu
_形式指定子で出力する必要があります。その部分を無視し、int
が4バイトであると仮定すると、
printf("sizeof(ch) %d\n",sizeof(ch));
は、Cで1、C++で1を出力します。
これは、両方の言語でchar
が定義ごとに1バイトであることが保証されているためです。
printf("sizeof('a') %d\n",sizeof('a'));
は、Cで4、C++で1を出力します。
これは、歴史的な理由により、文字リテラルの型がCのint
であるためです。1)、しかし、C++ではchar
型です。これは常識(およびISO 14882)が指示していることだからです。
printf("sizeof('a'+'b'+'C) %d\n",sizeof('a'+'b'+'C'));
は両方の言語で4を出力します。
Cでは、_int + int + int
_の結果の型は当然int
です。 C++では、_char + char + char
_があります。しかし、+は 暗黙の型昇格ルール を呼び出すため、結局はint
になります。
printf("sizeof(\"a\") %d\n",sizeof("a"));
は両方の言語で2を出力します。
文字列リテラル_"a"
_は、Cでは_char[]
_、C++では_const char[]
_型です。どちらの場合でも、a
とnullターミネータで構成される配列があります:2文字。
サイドノートとして、これは、配列_"a"
_がsizeof
へのオペランドのときに最初の要素へのポインターに減衰しないために発生します。たとえばsizeof("a"+0)
と書くことで配列の減衰を引き起こす場合、代わりにポインターのサイズ(おそらく4または8)を取得します。
1) 暗黒時代のどこかにタイプはなく、あなたが書いたものはすべてint
になります。その後、デニス・リッチーが何らかの方法でCの事実上の標準を作成し始めたとき、彼は文字リテラルは常にpromotedto int
。そして、Cが標準化された後、彼らは文字リテラルは単にint
であると言った。
C++を作成すると、Bjarne Stroustrupは、これらすべてがあまり意味をなさないことを認識し、文字リテラルをchar
と入力する必要がありました。しかし、C委員会はこの言語の欠陥の修正を頑なに拒否します。
他の人が述べたように、C言語標準は文字定数の型をint
に定義しています。これの歴史的な理由は、Cとその前身であるBが元々、8ビットASCIIをサポートしていたがレジスターでのみ演算を実行できたさまざまなWordサイズのDEC PDPミニコンピューターで開発されたためです。 Cのバージョンでは、int
がマシンのネイティブWordサイズであると定義されており、int
より小さい値はint
に拡張する必要があります。関数から、またはビット単位の論理式または算術式で使用されます。これは、基礎となるハードウェアがどのように機能したかによるものです。
また、整数プロモーションルールでは、int
よりも小さいデータ型はすべてint
に昇格すると言われています。 Cの実装では、同様の歴史的理由から、2の補数ではなく1の補数演算を使用することもできます。また、文字エスケープのデフォルトは8進数と8進数定数であり、0
および16進数の必要性\x
または0x
は、これらの初期のDECミニコンピューターでは、Wordのサイズが3バイトのチャンクに分割可能で、4バイトのニブルには分割できないということです。
int
への自動昇格は、今日の問題以外何も引き起こしません。 (2つのuint32_t
式は未定義の動作です。一部の実装ではint
を64ビット幅として定義しているため、言語ではint
よりも低いランクのすべてのタイプをsignedint
、2つのint
被乗数を乗算した結果の型はint
で、乗算は符号付き64ビットをオーバーフローさせる可能性があります製品、およびこれは未定義の動作ですか?)しかし、それがCとC++がそれで立ち往生している理由です。
コードはCでコンパイルされたと仮定しています。
Cでは、'a'
はint
型として扱われ、int
のサイズは4です。C++では、'a'
はchar
型として扱われ、cpp.shでコードをコンパイルしようとすると、1が返されます。