Тип выходных данных оператора sizeof () - PullRequest
0 голосов
/ 31 января 2019

Я использую Ubuntu 16.04.5 и GCC версии 5.4.0.

Я играл с оператором sizeof(), написал следующий код:

#include <stdio.h>

int main(int argc, char *argv[]){

        long int mylint = 31331313131.1313;

        printf("size of long int is %d\n", sizeof(mylint));
        printf("size of long int is %d\n", sizeof(long int));

        return 0;
}

Я попытался скомпилироватьиспользуя команду gcc -o ... ... и ожидал:

size of long int is 8
size of long int is 8

Но я получил следующую ошибку:

fl_double_lint.c: In function ‘main’:
fl_double_lint.c:11:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]

  printf("size of long int is %d\n", sizeof(mylint));
         ^
fl_double_lint.c:12:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
  printf("size of long int is %d\n", sizeof(long int));

Когда я использую %ld вместо этого, он работает, как ожидалось.Почему sizeof() не работает с %d?(Почему 'long unsigned int', а не 'int'?)

Редактировать: Я знаю, что было задано много вопросов относительно вывода оператора sizeof () (как это предлагается в комментариях),Однако они не отвечают на вопрос, почему использование %d не работает (т.е. не дает никакого результата).Я знаю, что это неправильный формат, но всякий раз, когда у нас есть переменная типа char, использующая %d, мы можем получить эквивалентный int результат, это также имеет место для short, uint8_t, uint16_t, uint32_t (обычно для типов с равнымили менее 32 бит).Следующий код работает:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]){

        char mychar = 'd';
        uint32_t myuint32 = 32;
        uint16_t myuint16 = 16;
        uint8_t myuint8 = 8;
        short myshort = 26945;
        int myint = 100;

        printf("integer equivalent of mychar is %d\n", mychar);
        printf("integer equivalent of myuint8 is %d\n", myuint8);
        printf("integer equivalent of myuint16 is %d\n", myuint16);
        printf("integer equivalent of myuint32 is %d\n", myuint32);
        printf("character equivalent of myint is %c\n", myint);
        printf("integer equivalent of myshort is %d\n", myshort);


        return 0;
}

Результат:

integer equivalent of mychar is 100
integer equivalent of myuint8 is 8
integer equivalent of myuint16 is 16
integer equivalent of myuint32 is 32
character equivalent of myint is d
integer equivalent of myshort is 26945

И теперь я обнаружил, что %d не работает для любой переменной, для хранения которой требуется больше 32 бит,После рассмотрения этого вопроса у меня есть некоторое представление о зависимости реализации size_t, возможно, в моей системе это было unsigned long (%ld также дает результат, подтверждающий это).Так что, может быть, если бы size_t было unsigned int в моей системе, я бы получил результат, это правда?

Как видно из приведенного выше кода, %c декодирует последние 8 бит int как символ, поэтому %d не делает то же самое (т.е. декодирует последние 32 бита содержимогопеременной size_t, как это было int? Я полагаю, что если бы это было так, мы могли бы получить тот же результат для достаточно малых чисел, и это было то, что я имел в виду, когда я первоначально задал вопрос).

1 Ответ

0 голосов
/ 31 января 2019

Оператор sizeof оценивает значение типа size_t.Этот тип не имеет знака и обычно больше int, поэтому вы получаете предупреждение.

Использование неверного спецификатора формата для printf вызывает неопределенное поведение .Однако это может сойти с рук для типов, меньших int из-за правил целочисленных повышений в разделе 6.3.1.1p2 стандарта C:

использоваться в выражении везде, где могут использоваться int или unsigned int:

  • Объект или выражение с целочисленным типом (кроме int или unsigned int), чей целочисленный коэффициент преобразования меньше или равензвание int и неподписанное int.
  • Битовое поле типа _Bool, int, sign int или unsigned int.

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

Таким образом, до тех пор, пока это не приведет к изменению с неподписанного на подписанное, типы, меньшие int, могут печататься с помощью %d.

Правильный модификатор типа для size_t равен %zu, в соответствии с разделом 7.21.6.1p7 стандарта C относительно модификаторов длины для функции fprintf (и, соответственно, printf):

z

Указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к size_t или соответствующему целочисленному типу со знакомаргумент;или что следующий n-й спецификатор преобразования применяется к указателю на целочисленный тип со знаком, соответствующий аргументу size_t.

Итак, вы хотите:

printf("size of long int is %zu\n", sizeof(mylint));
...