Тип выходных данных оператора sizeof ()

Я использую 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 результат, это также относится к коротким, 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? сделал бы так, чтобы мы могли получить тот же результат для достаточно малых чисел, и именно это я имел в виду, когда изначально задал вопрос).


person Adhamzhon Shukurov    schedule 31.01.2019    source источник
comment
Почему «long unsigned int», а не «int»? Какой смысл в отрицательном значении, возвращаемом из sizeof?   -  person Algirdas Preidžius    schedule 31.01.2019
comment
sizeof - это оператор, а не функция. Это результат типа size_t, а правильный спецификатор формата - %zu.   -  person Eugene Sh.    schedule 31.01.2019
comment
На самом деле "%ld" тоже неверно. Оператор sizeof возвращает значение типа size_t, и для его печати с помощью printf (и семейства) следует использовать "%zu". Или, поскольку вы также отметили этот вопрос совсем другим языком C ++, просто используйте std::cout << sizeof(something).   -  person Some programmer dude    schedule 31.01.2019
comment
@Eugene Sh Я редактировал, спасибо   -  person Adhamzhon Shukurov    schedule 31.01.2019
comment
@AdhamzhonShukurov Тип возвращаемого значения оператора sizeof - size_t без знака, а int по умолчанию подписан.   -  person antonyjr    schedule 31.01.2019
comment
Возможный дубликат Как оператор sizeof работает в C?   -  person YSC    schedule 31.01.2019
comment
Об этом спрашивали миллион раз. Золотые значки C: почему он до сих пор открыт ???   -  person YSC    schedule 31.01.2019
comment
Возможный дубликат Как правильно использовать printf для печати size_t?   -  person phuclv    schedule 01.02.2019
comment
size_t выглядит long unsigned int в вашей системе, но это не обязательно. Может быть unsigned short или unsigned int или любым другим, если он может представлять размер объектов на этой платформе.   -  person phuclv    schedule 01.02.2019
comment
@YSC это все еще дубликат?   -  person Adhamzhon Shukurov    schedule 01.02.2019
comment
@phuclv, можешь еще раз обдумать мой вопрос?   -  person Adhamzhon Shukurov    schedule 01.02.2019
comment
myuint32 - это uint32_t, который должен быть напечатан с использованием PRIu32. Помните, что int не всегда 32 бита, и печать беззнакового типа со спецификатором формата со знаком по-прежнему UB. спецификаторы формата printf для uint32_t и size_t   -  person phuclv    schedule 01.02.2019
comment
@phuclv Но до 2147483647 uint32_t и 32-битные целые числа декодировались одинаково. + Я спрашиваю, почему это даже не дает результата.   -  person Adhamzhon Shukurov    schedule 01.02.2019
comment
why %d does not do the same (i.e. decode the last 32 bits of content of size_t variable as it was int?) C так не работает. Размеры типов не фиксированы, и функции vararg не знают, какой размер у параметра. На платформах, где они находятся в стеке, если вы укажете другой тип, отличный от того, который вы ему дали, вы можете испортить стек, когда printf выдает другое количество байтов для этого аргумента. Как сказано, используйте правильный спецификатор и не удивляйтесь, почему он работает здесь, а не там   -  person phuclv    schedule 01.02.2019
comment
@phuclv Спасибо за ответ, но моя цель - использовать C вместе с аппаратным обеспечением, разработанным специально для HDL, поэтому для меня действительно важно задаться вопросом об этих вещах.   -  person Adhamzhon Shukurov    schedule 01.02.2019
comment
@phuclv Между прочим, дублирования связанного вопроса кажется недостаточно, чтобы полностью ответить на мой вопрос, я был бы рад, если вы удалите его (конечно, если вы согласны со мной).   -  person Adhamzhon Shukurov    schedule 01.02.2019


Ответы (1)


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

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

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

  • Объект или выражение с целочисленным типом (отличным от int или unsigned int), ранг целочисленного преобразования которого меньше или равен рангу int и unsigned int.
  • Битовое поле типа _Bool, int, signed 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));
person dbush    schedule 31.01.2019
comment
Я проголосовал против, так как в качестве золотого значка C я ожидал, что вы закроете этот вопрос как дубликат, а не ответите. - person YSC; 31.01.2019
comment
@YSC Не всегда легко найти один, если у вас нет конкретного в виду. Учитывая, что у этого есть заголовок, который лучше отражает вопрос, больше голосов и есть ответ с цитатой из стандарта, я отменяю дублирование. - person dbush; 31.01.2019
comment
Я нашел дубликат, выполнив поиск по запросу printf format sizeof. Первый ответ. Я не согласен с вами, но недостаточно решительно, чтобы что-либо сделать. - person YSC; 31.01.2019
comment
Я собираюсь закрыть другой вопрос, как обман, потому что я написал ответ здесь. Если вы думаете, что ваш ответ добавляет что-то к ответу на другой вопрос, переместите свой ответ туда. Это неправильно. - person Cris Luengo; 01.02.2019
comment
Учитывая, что вопросы (и их ответы) практически идентичны, лучше всего было бы попросить мод объединить их. (Я также частично согласен с @CrisLuengo в том, что вам, вероятно, не стоило задумываться над этим вопросом самостоятельно. Даже если это было объективно правильным решением - в чем я не уверен - он все равно < i> выглядит попыткой обыгрывать систему ради репутации и видимости.) - person Ilmari Karonen; 01.02.2019
comment
@dbush Спасибо за хороший ответ, он частично ответил на мой вопрос, но можете ли вы обновить его соответствующим образом и предоставить дополнительную информацию (я отредактировал вопрос). - person Adhamzhon Shukurov; 01.02.2019
comment
@AdhamzhonShukurov Нет, вы добавили еще вопрос к своему исходному вопросу. это не одобряется в Stack Overflow. Предпочитайте задавать новый вопрос. - person YSC; 01.02.2019
comment
@AdhamzhonShukurov Поскольку ваше редактирование требовало разъяснений по последней части вашего исходного вопроса, я обновил адрес. - person dbush; 01.02.2019