web-dev-qa-db-ja.com

sizeofの動作が文字と混同される

#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
45
AmanSharma

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)

各ケースを見てみましょう。

  1. chchar型であると定義されているため、非常に簡単です。

  2. Cでは、文字定数は整数型であるため、sizeof('a')sizeof (int)と同じです。

    C11を引用

    整数文字定数のタイプはintです。 [...]

    C++では、文字literalの型はcharです。

  3. sizeofはコンパイル時の演算子であるため(オペランドがVLAの場合を除く)、式のタイプが使用されます。前述のとおり、すべての整数文字定数はint型であるため、int + int + intintを生成します。したがって、オペランドのタイプはintとして扱われます。

  4. "a"は、2つのchars、'a'および0(null-terminator)(noの配列です。配列型の最初の要素へのポインタ)、したがって、サイズは2つのchar要素を持つ配列のサイズと同じです。


最後に、sizeofsize_t型の結果を生成するため、%zu形式指定子を使用して結果を出力する必要があります。

51
Sourav Ghosh

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型です。

23
Bathsheba

まず、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委員会はこの言語の欠陥の修正を頑なに拒否します。

9
Lundin

他の人が述べたように、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++がそれで立ち往生している理由です。

2
Davislor

コードはCでコンパイルされたと仮定しています。
Cでは、'a'int型として扱われ、intのサイズは4です。C++では、'a'char型として扱われ、cpp.shでコードをコンパイルしようとすると、1が返されます。

0
Wolf