Help us understand the problem. What is going on with this article?

[C言語] long int は 8byte と思い込んではいけない話

結論

タイトルがすべてを物語っています。long int 型のサイズは環境によって 4byte, 8byte の場合が考えられるという話です。

事の発端

SNSでこんな投稿を発見。

int a = LONG_MAX;
a と等しいものは?
1. INT_MAX
2. INT_MAX - 1
3. 0
4. INT_MIN

これを見た私の脳内フロー

  1. これは静的型付言語で、LONG_MAX は定数だろうからC言語だろう
  2. 定数 LONG_MAX は long int 型
  3. long int 型のサイズは 8byte だろう(本当か?)
  4. int a = LONG_MAX;の代入で暗黙の型変換(long int -> int)が行われる
  5. int 型のサイズは 4byte であり、long int 型のサイズより小さい(本当か?)。LONG_MAX = 2^63-1(本当か?)は 4byte では表現できないから、この暗黙の型変換は処理系依存では?

型変換に関しての詳細:初心者のためのポイント学習C言語, 少し詳しい型変換の説明

実験

環境

  • OS : windows10 x64
  • CPU : Intel Core i7-7500U
  • コンパイラ : MinGW gcc
  • コンパイルオプション : -g -Wall

実験1

long_int.c
#include <stdio.h>
#include <string.h>
#include <limits.h>

int main(void){

    int a[2];
    int b[2];

    memset(a, 0, 2 * sizeof(int));
    memset(b, 0, 2 * sizeof(int));

    long int max = LONG_MAX;

    // a[0] = max と同じ、暗黙の型変換あり
    *a = max;

    // 代入先の型情報を弄って型変換なし
    *((long int*)b) = max;

    printf("sizeof(long int) = %d\n", sizeof(long int));
    printf("LONG_MAX = %ld(0x%lx)\n",max,max);
    printf("a[0] = %d(0x%x)\n", a[0], a[0]);
    printf("a[1] = %d(0x%x)\n", a[1], a[1]);
    printf("b[0] = %d(0x%x)\n", b[0], b[0]);
    printf("b[1] = %d(0x%x)\n", b[1], b[1]);

    return 0;
}

実行結果

sizeof(long int) = 4
LONG_MAX = 2147483647(0x7fffffff)
a[0] = 2147483647(0x7fffffff)
a[1] = 0(0x0)
b[0] = 2147483647(0x7fffffff)
b[1] = 0(0x0)

環境によって、long int 型は 4byte だった。64bit 処理系では 8byte の場合が多いが、windowsは例外的に 4byte らしい。型変換も何もないではないか!

MaryCoew, 【C言語/C++】データ型のサイズ・範囲の一覧【32bit/64bit環境】

実験2

なら long long int型ならどうか。

long_long_int.c
#include <stdio.h>
#include <string.h>
#include <limits.h>

int main(void){

    int a[2];
    int b[2];
    int c[2];
    int d[2];

    memset(a, 0, 2 * sizeof(int));
    memset(b, 0, 2 * sizeof(int));
    memset(c, 0, 2 * sizeof(int));
    memset(d, 0, 2 * sizeof(int));

    long long int max = LLONG_MAX;

    // 暗黙の型変換あり
    *a = max;

    // 型変換なし
    *((long long int*)b) = max;

    // 暗黙の型変換の追加実験
    long long int test = 0x789abcdef0123456;
    *c = test;
    long long int* _d = (long long int*)d;
    *_d = test;

    printf("sizeof(long long int) = %d\n", sizeof(long long));
    printf("LLONG_MAX = %lld(0x%llx)\n",max,max);
    printf("a[0] = %d(0x%x)\n", a[0], a[0]);
    printf("a[1] = %d(0x%x)\n", a[1], a[1]);
    printf("b[0] = %d(0x%x)\n", b[0], b[0]);
    printf("b[1] = %d(0x%x)\n", b[1], b[1]);
    printf("test = %lld(0x%llx)\n", test,test);
    printf("c[0] = %d(0x%x)\n", c[0], c[0]);
    printf("c[1] = %d(0x%x)\n", c[1], c[1]);
    printf("d[0] = %d(0x%x)\n", d[0], d[0]);
    printf("d[1] = %d(0x%x)\n", d[1], d[1]);

}

実行結果

-Wallオプションを付けてコンパイルすると、unknown conversion type character 'l' in formatと警告がでますが無視です。

sizeof(long long int) = 8
LLONG_MAX = 9223372036854775807(0x7fffffffffffffff)
a[0] = -1(0xffffffff)
a[1] = 0(0x0)
b[0] = -1(0xffffffff)
b[1] = 2147483647(0x7fffffff)
test = 8690466096661279830(0x789abcdef0123456)
c[0] = -267242410(0xf0123456)
c[1] = 0(0x0)
d[0] = -267242410(0xf0123456)
d[1] = 2023406814(0x789abcde)

この結果を説明するにはエンディアン(バイトオーダー)の話が必要です。詳しくは、[バイトオーダー]ビックエンディアン/リトルエンディアン

a,cの暗黙の型変換がある場合、最下位 32bit がそのままコピーされている模様。実験の処理系は Little Endian であるため、サイズの小さな型に表現できない大きなサイズの値を代入するときメモリを順番に入るだけコピーしていると推定できます。

一方で、b,dの型変換がない場合は明白。Little Endian では最下位ビットから順に 1byte ずつメモリ上に並んでいるからです。

Seo-4d696b75
情報系の学生
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした