«Размер переменных типа C зависит от машины».Это правда?подписанные и неподписанные номера; - PullRequest
4 голосов
/ 28 марта 2010

Мне сказали, что типы C зависят от машины. Сегодня я хотел это проверить.

void legacyTypes()
{
    /* character types */
    char k_char = 'a';

        //Signedness --> signed & unsigned
        signed char k_char_s = 'a';
        unsigned char k_char_u = 'a';

    /* integer types */
    int k_int = 1; /* Same as "signed int" */

        //Signedness --> signed & unsigned
        signed int k_int_s = -2;
        unsigned int k_int_u = 3;

        //Size --> short, _____,  long, long long
        short int k_s_int = 4;
        long int k_l_int = 5;
        long long int k_ll_int = 6;

    /* real number types */
        float k_float = 7;
        double k_double = 8;
}

Я скомпилировал его на 32-битной машине с использованием компилятора minGW C

_legacyTypes:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $48, %esp
    movb    $97, -1(%ebp)  # char
    movb    $97, -2(%ebp)  # signed char
    movb    $97, -3(%ebp)  # unsigned char
    movl    $1, -8(%ebp)    # int
    movl    $-2, -12(%ebp)# signed int 
    movl    $3, -16(%ebp) # unsigned int
    movw    $4, -18(%ebp) # short int
    movl    $5, -24(%ebp) # long int
    movl    $6, -32(%ebp) # long long int
    movl    $0, -28(%ebp) 
    movl    $0x40e00000, %eax
    movl    %eax, -36(%ebp)
    fldl    LC2
    fstpl   -48(%ebp)
    leave
    ret

Я скомпилировал тот же код на 64-битном процессоре (Intel Core 2 Duo) на GCC (linux)

legacyTypes:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movb    $97, -1(%rbp) # char
    movb    $97, -2(%rbp) # signed char
    movb    $97, -3(%rbp) # unsigned char
    movl    $1, -12(%rbp) # int
    movl    $-2, -16(%rbp)# signed int 
    movl    $3, -20(%rbp) # unsigned int
    movw    $4, -6(%rbp)   # short int
    movq    $5, -32(%rbp) # long int
    movq    $6, -40(%rbp) # long long int
    movl    $0x40e00000, %eax
    movl    %eax, -24(%rbp)
    movabsq $4620693217682128896, %rax
    movq    %rax, -48(%rbp)
    leave
    ret

Наблюдения

  • char, знаковый символ, неподписанный символ, int, unsigned int, подписанный int, short int, unsigned short int, подписанный short int все занимают одно и то же значение no. байтов на 32-битном и 64-битном процессорах.

  • Единственное изменение в long int & long long int, оба из которых занимают 32-разрядную на 32-разрядной машине и 64-разрядную на 64-разрядной.

  • А также указатели, которые занимают 32-разрядные на 32-разрядных ЦП и 64-разрядные на 64-разрядных ЦП.

Вопросы:

  • Я не могу сказать, что книги говорят неправильно. Но я что-то здесь упускаю. Что именно означает «Типы переменных являются машинно-зависимыми?»
  • Как видите, нет разницы между инструкциями для неподписанных и подписанных номеров. Тогда почему диапазон номеров, к которым можно обратиться, используя оба, отличается?
  • Я читал Как сохранить фиксированный размер переменных типов C на разных машинах? Я не понял цели вопроса или его ответов. Какое сохранение фиксированного размера? Они все одинаковы. Я не понимаю, как эти ответы обеспечат одинаковый размер.

EDIT:

Разве нельзя обеспечить одинаковый размер для разных машин? Я имею в виду, как можно поддерживать одинаковый размер указателя как на 64-битной, так и на 32-битной машине?

Ответы [ 6 ]

8 голосов
/ 28 марта 2010

Существует намного больше платформ, и некоторые из них являются 16- или даже 8-битными! На них вы заметите гораздо большие различия в размерах всех вышеперечисленных типов.

Подписанные и неподписанные версии одного и того же базового типа занимают одинаковое количество байтов на любой платформе, однако их диапазон чисел различен, поскольку для числа со знаком один и тот же диапазон возможных значений распределяется между областью со знаком и без знака.

например. 16-разрядное целое число со знаком может иметь значения от -32767 (или -32768 на многих платформах) до 32767. Целое число без знака того же размера находится в диапазоне от 0 до 65535.

После этого, надеюсь, вы лучше поймете смысл поставленного вопроса. В основном, если вы пишете программу, предполагающую, что, например, ваши подписанные int-переменные смогут содержать значение 2 * 10 ^ 9 (2 миллиарда), ваша программа не переносима, потому что на некоторых платформах (16 бит и ниже) это значение вызовет переполнение, что приведет к молчанию и затруднению найти ошибки. Так, например на 16-битной платформе вам нужно #define ваши целые числа, чтобы быть long, чтобы избежать переполнения. Это простой пример, который может не работать на всех платформах, но я надеюсь, что он даст вам основную идею.

Причина всех этих различий между платформами заключается в том, что к тому времени, когда C стал стандартизированным, уже было много компиляторов C, используемых на множестве различных платформ, поэтому для обратной совместимости все эти разновидности должны были быть приняты как действительные.

7 голосов
/ 28 марта 2010

Зависит от машины не совсем точно. На самом деле, определяется реализацией . Это может зависеть от компилятора, машины, опций компилятора и т. Д.

Например, при использовании Visual C ++ long будет 32-битным даже на 64-битных машинах.

4 голосов
/ 28 марта 2010

Что именно означает "Типы переменных зависят от машины?"

Это означает именно то, что говорится: размеры большинства целочисленных типов C зависят от машины (на самом деле не машина , а архитектура и компилятор). Когда я делал много C в начале 90-х, int был в основном 16 битами; сейчас это в основном 32 бита. Раньше, чем моя карьера в Си, это могло быть 8 бит. И т.д.

Очевидно, что разработчики компилятора C, который вы используете для 64-битной компиляции, решили, что int должно остаться 32-битным. Разработчики другого компилятора Си могут сделать другой выбор.

1 голос
/ 28 марта 2010

Это нечто другое, совсем другое, чем вы привыкли, но то, которое все еще присутствует в Интернете сегодня, даже если оно больше не используется для вычислений общего назначения, за исключением любителей ретро-вычислений - Нет Размеры такие же, как у вас:

@type sizes.c
#include <stdio.h>
#include <limits.h>

int main()
{
   printf("CHAR_BIT = %d\n", CHAR_BIT);
   printf("sizeof(char) = %d\n", sizeof(char));
   printf("sizeof(short) = %d\n", sizeof(short));
   printf("sizeof(int) = %d\n", sizeof(int));
   printf("sizeof(long) = %d\n", sizeof(long));
   printf("sizeof(float) = %d\n", sizeof(float));
   printf("sizeof(double) = %d\n", sizeof(double));
   return 0;
}
@run sizes.exe
CHAR_BIT = 9
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4
sizeof(float) = 4
sizeof(double) = 8
1 голос
/ 28 марта 2010

Реальные компиляторы обычно не пользуются всеми вариациями, разрешенными стандартом. Требования стандарта просто дают диапазон минимум для типа - 8 бит для символа, 16 бит для короткого и целого, 32 бита для длинного и (в C99) 64 бита для длинного ( каждый тип в этом списке должен иметь как минимум такой же большой диапазон, как и предыдущий тип).

Однако для настоящего компилятора обратная совместимость почти всегда является главной целью. Это означает, что у них есть сильная мотивация, чтобы изменить как можно меньше. В результате на практике между компиляторами гораздо больше общего, чем требует стандарт.

1 голос
/ 28 марта 2010

Если бы вы повторили свой тест, скажем, на процессоре Motorola 68000, вы бы обнаружили, что вы получите другие результаты (со словом 16 бит и длинным 32 - как правило, int - это слово)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...