предупреждающие сообщения при компиляции c-программы с использованием gcc [closed]

6

Я новичок в Linux. Я использую gcc (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3 на Ubuntu 12.04 LTS. Когда я скомпилировал программу c с помощью указателя, я получил предупреждение -Wformat , как показано ниже. Но если я выполню файл a.out , я получаю правильный результат. Может кто-нибудь, пожалуйста, скажите мне, почему я получил сообщение и предложил мне, что я должен сделать, чтобы победить?

Моя программа тестирования:

 #include<stdio.h>

void main(void)

{

int x=10,y,z;
int *p=&x ;

        printf("\n\np  = %u\n",p);
        printf("\n*p = %u\n",*p);
        printf("\n&x = %u\n",&x);
        printf("\n&y = %u\n",&y);
        printf("\n&z = %u\n",&z);
        printf("\n&p = %u\n\n",&p);
}

Вывод:

qust1-Array.c:11:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:14:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:15:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:16:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:17:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat]
    
задан Thilipkumar 01.04.2013 в 14:38
источник

1 ответ

5

Вы получаете предупреждения, потому что вы используете неверный спецификатор формата в printf() . p - целочисленный указатель. &p - адрес указателя. &x и &y - адреса целых чисел. Это все адреса в памяти, а не значения переменной. Спецификатор %u для значений целых чисел без знака. Таким образом, вы печатаете яблоки, где компилятор ожидает апельсины. Адреса короче, чем некоторые значения, хранящиеся в переменных. При использовании %u фактически напечатает значение адреса как десятичное (очень необычное) и еще несколько данных, расположенных позади этого в памяти. Компилятор жалуется, потому что это, вероятно, не то, что вы хотите сделать. Для печати адресов используйте спецификатор %p , как в:

printf("\n&x = %p\n",&x);

Кроме того, ваши переменные являются целыми целыми числами и как таковые должны использовать %i вместо %u . Спецификатор формата %u printf() предназначен только для целых положительных чисел. Для малых положительных значений, %i и %u взаимозаменяемы. Предупреждение отображается, потому что тип переменной не соответствует его спецификатору, и в некоторых случаях это вызывает проблемы.

Это будет более разумно из ваших типов переменных:

printf("\n\np  = %p\n",  p); // p is a pointer so %p would print the address

printf("\n*p = %i\n",   *p); // the data saved at that address is an integer 
                             // so %i is appropriate if you dereference the 
                             // pointer with the star "*p"

printf("\n&x = %p\n",   &x); // &x gives the address of the integer variable x 
                             // so %p is the specifier for that address

printf("\n&y = %p\n",   &y);
printf("\n&z = %p\n",   &z);

printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is 
                             // stored -> still an address -> %p is the right
                             // specifier

Битовый фон для целых чисел и указателей без знака:

C использует один и тот же 32-разрядный (или другой уровень мощности в два в зависимости от архитектуры системы) для хранения целых чисел без знака и подписи. Таким образом, наибольший unsigned int равен 2 32 -1 или в двоичной нотации:

  

2 32 -1 = (11111111111111111111111111111111) 2 & lt; - (без знака)

И номер один будет выглядеть так в двоичном формате:

  

1 = (00000000000000000000000000000001) 2 & lt; - (без знака)

Теперь регулярные знаковые целые числа также должны хранить отрицательные числа, но все же в том же пространстве 32 бит. Если вы сохранили знак, числа, например. первый бит, вы потеряете целое число. Это было бы расточительно, например. нуль имел бы два представления как + и - ноль. Чтобы обойти эту проблему, отрицательные числа в целых числах хранятся немного иначе . Чтобы закодировать число в целое число со знаком, вы добавляете половину возможного диапазона для вашего 32-битного числа. Это 2 (32-1) , а затем используйте регулярное двоичное представление этого нового числа. Таким образом, один кодируется как 2 (32-1) + 1 для целого числа без знака. Мы имеем:

  

2 (32-1) = (11111111111111111111111111111111) 2 & lt; -signed

     

...

     

1 = (10000000000000000000000000000001) 2 & lt; - подписанный

     

0 = (10000000000000000000000000000000) 2 & lt; - подписанный

     

-1 = (01111111111111111111111111111111) 2 & lt; - подписанный

     

...

     

-2 (32-1) = (00000000000000000000000000000000) 2 & lt; -signed

Теперь вы закодировали одинаковое число целых чисел, но максимум для целых чисел со знаком, следовательно, будет только 2 (32-1) , а не double, что 2 32 -1, для целых чисел без знака. Это называется выражением over-K или offset-binary для отрицательных чисел. В большинстве систем используется дополнение Two , где первый, самый старший бит отменяется.

Чтобы увидеть это, установите x=-1; , а затем printf("%u",x) . Вы получите следующий результат:

  

2147483648

Что такое 2 32-1 или (01111111111111111111111111111111) 2 в двоичной записи. Для дополнения Two это число будет:

  

4294967295

Или 2 32 -1. Это равно (1111111111111111111111111111111111) 2 в двоичном формате, поэтому он имеет первый бит, противоположный по сравнению с вышеуказанным избыточным значением K 2147483648.

Итак, это как данные хранятся. Указатели вступают в игру, когда вы думаете о , где . Физические биты в памяти должны иметь адреса. Поскольку их невероятно много, вы обращаетесь к ним в кусках более одного раза. Если вы создаете указатель, физическая память по адресу указателя содержит другой адрес в памяти. Таким образом, дом - это физический объект, очень похожий на память вашего ПК. Бумага будет указателем. Он меньше, чем дом, но может содержать адрес дома или других домов. В этой аналогии, выше, вы попытались бы снести лист бумаги вместо фактического дома, и на самом деле это была гора ...

    
ответ дан con-f-use 01.04.2013 в 16:09
источник