Поведение printf при передаче структурной переменной на языке Си - PullRequest
2 голосов
/ 23 июня 2010

Я пытался программой понять поведение структурной переменной,

Пример кода:

struct temp
{
   int a;
   int b;
}obj;

int main()
{
   obj.a = 10;
   obj.b = 7;
   /* to see whether obj and &obj both are same 
    * I was verifying whether structure variables behave as arrays
    */
   printf("%d -- %p",obj,&obj); 
   return 0;
}

Я ожидал, что результат будет 10 и адрес obj Но к моему удивлению,Фактический результат равен 10 и 00000007

Это меня сейчас очень беспокоит !!!

Может кто-нибудь помочь мне понять, почему printf берет второй элемент и печатает его значение.

Ответы [ 4 ]

7 голосов
/ 23 июня 2010

Это происходит потому, что первый параметр должен иметь 4 байта (целое число), но он имеет 8 байтов (struct obj).

Когда вы передаете obj функции printf, она поместит в стек всю структуру obj (включая член b). Таким образом, при печати это займет первые 4 байта в стеке для первого параметра (obj.a) и следующие 4 байта в стеке (obj.b) для второго параметра.

Проверьте это:

printf("%d %p %p\n", obj, &obj, &obj);
6 голосов
/ 23 июня 2010

Потому что вы помещаете obj в стек. Другими словами, вы помещаете туда целые числа 10 и 7, и одно из них используется для %d, другое для %p. Фактический указатель вообще не используется.

Измените строку на:

printf("%d %d -- %p\n",obj,&obj);

и вы получите что-то вроде:

10 7 -- 0x804a01c

, который имеет правильный адрес:

Вот изображение, чтобы помочь:

What you push                 What printf uses
               +------------+
     /         |         10 |      %d
obj <          +------------+
     \         |          7 |      %p
               +------------+
&obj           | 0x80001234 |      not-used
               +------------+

Я видел подобные проблемы, когда люди передают long в printf с целочисленным форматом %d. %d использует только первую часть long, а вторая часть - все остальные аргументы. Подробнее см. здесь .

Вот почему у gcc есть те милые маленькие согревающие сообщения, которые появляются при несовпадении типов со спецификаторами в семействе функций printf:

qq.c: In function ‘main’:
qq.c:14: warning: incompatible implicit declaration of built-in function ‘printf’
qq.c:14: warning: format ‘%d’ expects type ‘int’, but argument 2
                  has type ‘struct temp’
5 голосов
/ 23 июня 2010

Вы могли бы потратить много времени, пытаясь выяснить, почему ваш printf печатает то, что печатает, и даже понять все, только чтобы позже выяснить, в вашем следующем эксперименте, что объяснение, которое было совершенно ясно для вас, больше не работает и вы должны начать все с нуля.

Настоящее и универсально применимое объяснение в этом случае заключается в том, что ваш код выдает неопределенное поведение . Вы указали спецификатор формата %d для функции printf. Это означает, что соответствующий аргумент должен иметь тип int, только int и ничего, кроме int. Вместо int вы указали объект типа struct temp. struct temp не является int. Как только вы это сделаете, поведение вашего кода не определено. Он может печатать абсолютно все без какой-либо значимой причины. Он ничего не может напечатать. Это может привести к сбою. Формально он может даже отформатировать ваш жесткий диск. Поведение не определено. Это означает, что даже если вам удастся «понять» поведение вашей программы сегодня, она может случайно измениться завтра только потому, что изменилась погода, изменилась дата в календаре или изменилась версия вашего компилятора.

Короче говоря, ваш код не имеет смысла (особенно из-за проблемы со спецификатором формата). Попытка разобрать поведение бессмысленного кода - пустая трата времени.

1 голос
/ 23 июня 2010

Функция printf принимает переменное количество аргументов.Это означает, что он не знает, какие параметры вы передали ему во время компиляции.Вместо этого он пытается реализовать это во время выполнения, анализируя строку формата, которую вы передали.

printf("%d -- %p",obj,&obj);

Приведенный выше код перемещает структуру obj на значение, которое имеет размер двух целых чисел.Плюс его адрес, который использует размер еще одного целого числа (при условии 32-битной архитектуры).

С другой стороны, в соответствии со строкой формата вам нужно было передать ему одно целое число и один адрес.* Вы только что перепутали это.Второй элемент структуры b считается вторым переданным параметром и печатает его как указатель.Это объясняет 00000007.

Вот что вам нужно было сделать:

printf("%d -- %p",obj.a,&obj);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...