Тип данных C int и его разновидности - PullRequest
1 голос
/ 06 апреля 2011

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

Код:

    #include <stdio.h>

    int main(void)
   {
    int Fnum = 256; /* The First number to be printed out */

    printf("The number %d in long long specifier is %lld\n" , Fnum , Fnum);

    return 0;
   }

Вопрос:

1.) Этот код вызвал у меня предупреждение при попытке запустить этот код.

2.) Ностранно то, что когда я пытаюсь изменить спецификатор %lld на %hd или %ld, предупреждающее сообщение не отображалось во время выполнения, и значение, выводимое на консоль, является правильной цифрой 256 все также кажется нормальным, даже если я пытаюсь использовать %u, %hu, а также %lu. Короче говоря, предупреждающее сообщение и неправильная печать цифры происходят только при использовании варианта спецификатора long long.

3.) Почему это происходит? Я думал, что размер памяти long long достаточно велик, чтобы содержать значение 256 , но почему его нельзя использовать для распечатки соответствующего значения??

Предупреждение Mesмудрец: (для приведенного выше исходного кода)

C:\Users\Sam\Documents\Pelles C Projects\Test1\Test.c(7): warning #2234: Argument 3 to 'printf' does not match the format string; expected 'long long int' but found 'int'.

Спасибо, что потратили время на чтение моего вопроса. Бог благословит.

Ответы [ 4 ]

6 голосов
/ 06 апреля 2011

Вы передаете переменную Fnum в printf, которая набирается int, но она ожидает long long. Это очень мало связано с тем, может ли long long удерживать 256, только то, что выбранная вами переменная имеет тип int.

Если вы просто хотите напечатать 256, вы можете получить константу, набранную в unsigned long long следующим образом:

printf("The number %d in long long specifier is %lld\n" ,256 , 256ULL);

или актерский состав:

printf("The number %d in long long specifier is %lld\n" , Fnum , (long long int)Fnum);
3 голосов
/ 06 апреля 2011

Здесь происходит три вещи.

  1. printf принимает переменное число аргументов.Это означает, что компилятор не знает, какого типа должны быть аргументы (кроме строки формата).Поэтому он не может преобразовать их в соответствующий тип.
  2. Однако по историческим причинам целочисленные типы, меньшие int, "повышаются" до int при передаче в списке переменных аргументов.
  3. Вы, похоже, используете Windows.В Windows int и long имеют одинаковый размер, даже когда указатели имеют ширину 64 бита (это преднамеренное нарушение C89 со стороны Microsoft - они фактически вынудили изменить стандарт в C99, чтобы сделать его «нормальным»)).

Результатом всего этого является то, что компилятору не разрешается преобразовывать ваш int в long long только потому, что вы использовали %lld в списке аргументов.(Разрешается предупредить вас, что вы забыли приведение, потому что предупреждения не соответствуют стандартному поведению.) Следовательно, при %lld ваша программа не работает.Но если вы используете какой-либо другой спецификатор размера, printf завершает поиск аргумента того же размера, что и int, и он работает.

1 голос
/ 06 апреля 2011

Это связано с тем, как varargs работает в C. В отличие от обычной функции, printf() может принимать любое количество аргументов. Программист должен сказать printf(), чего ожидать, предоставив правильную строку формата.

Внутренне printf() использует спецификаторы формата для доступа к необработанной памяти, которая соответствует входным аргументам. Если вы укажете %lld, он попытается получить доступ к 64-битному фрагменту памяти (в Windows) и интерпретировать то, что он находит, как long long int. Однако вы указали только 32-битный аргумент, поэтому результат будет неопределенным (он объединит ваш 32-битный int с любым случайным мусором, который окажется следующим в стеке).

1 голос
/ 06 апреля 2011

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

В некоторых случаях вы можете использовать немного разные типы аргументов. Например, если вы передадите short, то оно неявно преобразуется в int. И когда sizeof (int) == sizeof (long int), то также нет никакого различия. Но sizeof (int)! = Sizeof (long long int), поэтому параметр не может соответствовать строке формата в этом случае.

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