65

sizeofオペレーターが次の結果を生成する理由がわかりません。

sizeof( 2500000000 ) // => 8 (8 bytes).

... 8 を返します。次の操作を行うと、次のようになります。

sizeof( 1250000000 * 2 ) // => 4 (4 bytes).

... 8 ではなく 4 を返します (これは私が期待していたものです)。sizeof式 (またはデータ型) のサイズを決定する方法と、特定のケースでこれが発生する理由を誰かが明確にすることはできますか?

私の最良の推測は、sizeofオペレーターがコンパイル時のオペレーターであるということです。

報奨金の質問:これらの式を評価し、(キャストせずに) 期待される出力を生成できる実行時演算子はありますか?

4

8 に答える 8

123

2500000000は に適合しないため、コンパイラはそれを(または、または適合する型)intとして正しく解釈します。あり、そうです。パラメータ toは評価されないため、コンパイラは乗算が に収まらないことをおそらく認識できないため、 のサイズを返します。longlong long12500000002sizeof intint

また、パラメーターが評価された場合でも、オーバーフロー (および未定義の動作) が発生する可能性がありますが、それでも4.

ここ:

#include <iostream>
int main()
{
    long long x = 1250000000 * 2;
    std::cout << x;
}

出力を推測できますか?だと思ったら大2500000000間違い。式の型はです。これ1250000000 * 2int、オペランドがintandintであり、乗算が適合しない場合、より大きなデータ型に自動的に昇格されないためです。

http://ideone.com/4Adf97

ここで、gcc はそれ-1794967296が であると言いますが、これは未定義の動作であるため、任意の数になる可能性があります。この数は に収まりintます。

さらに、オペランドの 1 つを予想される型にキャストすると (整数以外の結果を探している場合に除算時に整数をキャストするのと同じように)、これが機能することがわかります。

#include <iostream>
int main()
{
    long long x = (long long)1250000000 * 2;
    std::cout << x;
}

正しい が得られます2500000000

于 2013-05-30T04:37:32.283 に答える
2

フォローアップの質問については、「演算子」はなく、式の「コンパイル時」サイズと「実行時」サイズに違いはありません。

特定のタイプが探している結果を保持できるかどうかを知りたい場合は、いつでも次のようなことを試すことができます。

#include <stdio.h>
#include <limits.h>

int main(void) {
    int a = 1250000000;
    int b = 2;

    if ( (INT_MAX / (double) b) > a ) {
        printf("int is big enough for %d * %d\n", a, b);
    } else {
        printf("int is not big enough for %d * %d\n", a, b);
    }

    if ( (LONG_MAX / (double) b) > a ) {
        printf("long is big enough for %d * %d\n", a, b);
    } else {
        printf("long is not big enough for %d * %d\n", a, b);
    }

    return 0;
}

そして、(少し)より一般的な解決策は、ひばりのためだけです:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

/* 'gssim' is 'get size of signed integral multiplication */

size_t gssim(long long a, long long b);
int same_sign(long long a, long long b);

int main(void) {
    printf("size required for 127 * 1 is %zu\n", gssim(127, 1));
    printf("size required for 128 * 1 is %zu\n", gssim(128, 1));
    printf("size required for 129 * 1 is %zu\n", gssim(129, 1));
    printf("size required for 127 * -1 is %zu\n", gssim(127, -1));
    printf("size required for 128 * -1 is %zu\n", gssim(128, -1));
    printf("size required for 129 * -1 is %zu\n", gssim(129, -1));
    printf("size required for 32766 * 1 is %zu\n", gssim(32766, 1));
    printf("size required for 32767 * 1 is %zu\n", gssim(32767, 1));
    printf("size required for 32768 * 1 is %zu\n", gssim(32768, 1));
    printf("size required for -32767 * 1 is %zu\n", gssim(-32767, 1));
    printf("size required for -32768 * 1 is %zu\n", gssim(-32768, 1));
    printf("size required for -32769 * 1 is %zu\n", gssim(-32769, 1));
    printf("size required for 1000000000 * 2 is %zu\n", gssim(1000000000, 2));
    printf("size required for 1250000000 * 2 is %zu\n", gssim(1250000000, 2));

    return 0;
}

size_t gssim(long long a, long long b) {
    size_t ret_size;
    if ( same_sign(a, b) ) {
        if ( (CHAR_MAX / (long double) b) >= a ) {
            ret_size = 1;
        } else if ( (SHRT_MAX / (long double) b) >= a ) {
            ret_size = sizeof(short);
        } else if ( (INT_MAX / (long double) b) >= a ) {
            ret_size = sizeof(int);
        } else if ( (LONG_MAX / (long double) b) >= a ) {
            ret_size = sizeof(long);
        } else if ( (LLONG_MAX / (long double) b) >= a ) {
            ret_size = sizeof(long long);
        } else {
            ret_size = 0;
        }
    } else {
        if ( (SCHAR_MIN / (long double) llabs(b)) <= -llabs(a) ) {
            ret_size = 1;
        } else if ( (SHRT_MIN / (long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(short);
        } else if ( (INT_MIN / (long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(int);
        } else if ( (LONG_MIN / (long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(long);
        } else if ( (LLONG_MIN / (long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(long long);
        } else {
            ret_size = 0;
        }
    }
    return ret_size;
}

int same_sign(long long a, long long b) {
    if ( (a >= 0 && b >= 0) || (a <= 0 && b <= 0) ) {
        return 1;
    } else {
        return 0;
    }
}

私のシステムでは、次のように出力されます。

size required for 127 * 1 is 1
size required for 128 * 1 is 2
size required for 129 * 1 is 2
size required for 127 * -1 is 1
size required for 128 * -1 is 1
size required for 129 * -1 is 2
size required for 32766 * 1 is 2
size required for 32767 * 1 is 2
size required for 32768 * 1 is 4
size required for -32767 * 1 is 2
size required for -32768 * 1 is 2
size required for -32769 * 1 is 4
size required for 1000000000 * 2 is 4
size required for 1250000000 * 2 is 8
于 2013-08-14T19:42:26.427 に答える
2

答えを言い換える別の方法は、関連するsizeofのは式の値ではなく、型であると言うことです。sizeof型または式として明示的に指定できる型のメモリ サイズを返します。この場合、コンパイラは実際に式を計算せずにコンパイル時にこの型を計算します (たとえば、関数を呼び出す場合、結果の型は返される値の型になります)。

他の投稿者が述べたように、可変長配列には例外があります (型のサイズは実行時にしかわかりません)。

言い換えれば、通常、式が L 値であるsizeof(type)orのようなものを記述します。sizeof expression式が複雑な計算になることはほとんどありません (上記の関数呼び出しのばかげた例のように) : とにかく評価されないので役に立たないでしょう。

#include <stdio.h>

int main(){
    struct Stype {
            int a;
    } svar;
    printf("size=%d\n", sizeof(struct Stype));
    printf("size=%d\n", sizeof svar);
    printf("size=%d\n", sizeof svar.a);
    printf("size=%d\n", sizeof(int));

}

また、sizeof は言語キーワードであるため、関数ではなく、末尾の式の前に括弧を付ける必要がないことに注意してください (return キーワードにも同じ種類の規則があります)。

于 2013-05-30T09:21:14.150 に答える
0

C11 ドラフトはこちら: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf Cx0 ドラフトはこちら: http://c0x.coding-guidelines.com /6.5.3.4.html

どちらの場合も、セクション 6.5.3.4 が探しているものです。基本的に、あなたの問題はこれに要約されます:

// Example 1:
long long x = 2500000000;
int size = sizeof(x); // returns 8

// Example 2:
int x = 1250000000;
int y = 2;
int size = sizeof(x * y); // returns 4

例 1 では、long long(8 バイト) があるため、8 が返されます。例 2 では、4 バイトのint * intを返す があります (つまり、4 が返されます)。int

報奨金の質問に答えるには: はい、いいえ。 sizeof実行しようとしている操作に必要なサイズは計算されませんが、適切なラベルを使用して操作を実行すると、結果のサイズがわかります。

long long x = 1250000000;
int y = 2;
int size = sizeof(x * y); // returns 8

// Alternatively
int size = sizeof(1250000000LL * 2); // returns 8

処理している数が多いことを伝える必要があります。そうしないと、処理できる最小の型 (この場合はint) を処理していると見なされます。

于 2013-08-14T19:43:46.910 に答える
0

1行の最も簡単な答えは次のとおりです。

sizeof() は COMPILE TIME に評価される関数で、入力は ac 型であり、その値は完全に無視されます

詳細: ..したがって、2500000000 がコンパイルされると、int に収まるには長すぎるため、LONG として格納する必要があります。したがって、この引数は単純に「(type) long」としてコンパイルされます。ただし、1250000000 と 2 は両方とも型 'int' に適合するため、これが sizeof に渡される型です。コンパイラが単に型に関心があるため、結果の値が格納されることはなく、乗算が評価されることはありません。

于 2016-10-26T18:36:21.623 に答える
0

はい、 sizeof() は、その乗算の結果に必要なメモリを計算しません。

2 番目のケースでは、両方のリテラル :12500000002それぞれが4 bytesメモリを必要とするため、sizeof() は を返します4。値の 1 つが を上回っていた場合は4294967295 (2^32 - 1)、 が得られ8ます。

しかし、 sizeof() が に対してどのように返さ8れたかはわかりません25000000004私のVS2012コンパイラで返されます

于 2013-05-30T04:50:55.847 に答える