Я новичок в 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]
Вы получаете предупреждения, потому что вы используете неверный спецификатор формата в 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 sup> -1 или в двоичной записи :
2 32 < / sup> -1 = (11111111111111111111111111111111) 2 < - (без знака)
blockquote>И число номер один будет выглядеть в двоичном виде:
& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; 1 = (00000000000000000000000000000001) 2 < - (unsigned)
blockquote>Теперь регулярно целые числа со знаком также должны хранить отрицательные числа, но все еще в том же 32-битном пространстве. Если вы сохранили знак числа, например, в Во-первых, вы бы потеряли целую часть. Это было бы расточительно, например ноль будет иметь два представления в виде + и - ноль. Чтобы обойти эту проблему отрицательные числа в знаковых целых числах хранятся немного по-другому : Чтобы закодировать число в целое число со знаком, вы добавляете половину возможного диапазона для вашего 32-разрядного числа. Это 2 (32-1) sup>, а затем использовать обычное двоичное представление этого нового числа. Таким образом, единица кодируется как 2 (32-1) sup> + 1 для целого числа без знака. У нас есть:
& nbsp; 2 (32-1) sup> = (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) sup> = (00000000000000000000000000000000) 2 -signed
blockquote>Теперь вы закодировали то же число целые числа, но максимум для целых чисел со знаком составляет, следовательно, только 2 (32-1) sup>, в отличие от двойного значения, 2 32 sup> -1, для целых чисел без знака. Это называется избыточным-K или смещенным двоичным представлением для отрицательных чисел. Большинство систем используют дополнение Two , где первый, самый старший бит инвертируется.
Чтобы увидеть это, установите
x=-1;
, а затемprintf("%u",x)
. Вы получите следующий вывод:2147483648
blockquote>, который равен 2 32-1 sup> или (01111111111111111111111111111111) 2 ] в двоичной записи. Для дополнения к двум это число будет:
4294967295
blockquote>или 2 32 sup> -1. Это равно (11111111111111111111111111111111) 2 в двоичном формате, поэтому первый бит поменялся местами по сравнению со значением выше избыточного K, равным 2147483648.
Итак, как хранятся данные. Указатели вступают в игру, когда вы думаете о , где . Физические биты в памяти должны иметь адреса. Поскольку их невероятно много, вы обращаетесь к ним более чем одним битом. Если вы создаете указатель, физическая память по адресу указателя содержит другой адрес в памяти. Таким образом, дом - это физический объект, очень похожий на память вашего ПК. Кусок бумаги будет указателем. Он меньше, чем дом, но может содержать адрес дома или других домов. В этой аналогии выше вы бы попытались снести лист бумаги вместо реального дома, а на самом деле это была гора ...