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

Я новичок в 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]
6
задан 1 April 2013 в 20:54

1 ответ

Вы получаете предупреждения, потому что вы используете неверный спецификатор формата в 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 < / sup> -1 = (11111111111111111111111111111111) 2 < - (без знака)

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

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; 1 = (00000000000000000000000000000001) 2 < - (unsigned)

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

& nbsp; 2 (32-1) = (11111111111111111111111111111111) 2 - подписано

& nbsp; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; ...

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; nbsp; 1 = (10000000000000000000000000000001) 2 < - подписано

[nbsp; nbsp; nbsp; nbsp; ; & nbsp; & nbsp; & nbsp; & nbsp; 0 = (10000000000000000000000000000000) 2 - подписано

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

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; ...

-2 (32-1) = (00000000000000000000000000000000) 2 -signed

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

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

2147483648

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

4294967295

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

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

0
ответ дан 1 April 2013 в 20:54

Другие вопросы по тегам:

Похожие вопросы: