Printf для структуры?(C / C ++, VC2008) - PullRequest
5 голосов
/ 02 ноября 2010

Просто соберите и запустите это в VC2008:

struct A
{
   int a;
   int b;
   int c;
};
A a = { 10, 20, 30 };
printf("%d %d %d\n", a);

Это нормально?

10 20 30

Я бы хотел сыграть! но это не работает:

struct A
{
   int a;
   int b;
   int c;
   operator int()
   {
      return a + b + c;
   }
};
A a = { 10, 20, 30 };
printf("%d\n", a);

вывод только:

10

Мне нужно автоматическое приведение для шаблона-утилиты. Вот оно: https://code.google.com/p/boolib/source/browse/boolib/crypt/ShakedValue.h Он должен скрывать в памяти значение, что никакие хак-программы (ArtMoney) не могут найти значение.

И еще один прием: Печать приватных членов структуры / класса

Ответы [ 8 ]

10 голосов
/ 02 ноября 2010

Если вы хотите сыграть, то разыграйте:

struct A
{
   int a;
   int b;
   int c;
   operator int()
   {
      return a + b + c;
   }
};
A a = { 10, 20, 30 };
printf("%d\n", (int)a);

вывод будет

60
5 голосов
/ 02 ноября 2010

Нет такой вещи, как C / C ++, ваш код - просто смесь двух.В частности, он не компилируется со стандартным компилятором C, потому что вам не хватает ключевого слова struct в объявлении a.

Для использования printf.Прежде всего, вы не должны, если это C ++.У него свои механизмы для IO.Используйте их.

Тогда размещение структуры в качестве аргумента в списке ... является неопределенным поведением.Вам просто не повезло, и компилятор сделал то, что сделал.Это могло бы просто вызвать грустное «нет, нет, не делай этого» или, по крайней мере, дать вам предупреждение.

5 голосов
/ 02 ноября 2010

Это неопределенное поведение, поэтому в определенном смысле каждое возможное поведение можно назвать «нормальным» для этого вызова функции.Это можно объяснить, хотя.

printf принимает переменное число аргументов после строки формата.Как они упакованы, оставлено для реализации.Кажется, что Visual C ++ упаковывает аргументы в памяти так же, как упаковывает элементы вашего struct A, поэтому каждый раз, когда он вызывает va_arg внутри, он получает следующий элемент a.

* 1008Что касается приведения, вы не можете полагаться на автоматическое вещание в контексте varargs, так как необязательные параметры не имеют типа.printf объявлено как int printf(char const *, ...).... - это диапазон нетипизированных параметров.
4 голосов
/ 02 ноября 2010

Вы поместили три целых числа в стек, а затем получили три целых числа (по одному на "% d").Да, это нормально - но в сфере «действительно безобразный хак» (и неопределенного поведения при загрузке, как правильно прокомментировал плинтус).

3 голосов
/ 02 ноября 2010

Это работает случайно.В большинстве случаев, когда printf число аргументов или типы не совпадают, результаты не будут хорошими.

Если вы хотите C ++, используйте ostream/cout

std::cout << a.a << ' ' << a.b << ' ' << a.c << std::endl;

Если вы хотите не хрупкиеИспользование кода C:

printf("%d %d %d\n", a.a, a.b, a.c);
2 голосов
/ 02 ноября 2010

Есть много вещей, зависящих от компилятора / среды, в поведении printf.

printf якобы использует функции var args C, когда у вас есть объявление

 int printf(char* formatStr, ...)

Вы можете передать несколько аргументов в "...". Затем в теле printf вы должны сделать что-то вроде следующего:

// count how many formatters are in the format string 
// and calculate "amount"
// here amount = 3
va_list valsToPrint;
va_start(valsToPrint,amount);    
for (int i = 0; i < amount; ++i)
{
    // treat each value as a 32-bit int and print it
}

va_end(vl);

Важно то, что здесь много чего зависит от компилятора / среды. Например, тот факт, что структура, вероятно, упакована так, что каждое значение отображается на 32-битных границах, и как va_list фактически определяется из компилятора. Я предполагаю, что компилятор-компилятор может отличаться от вашего кода, но неудивительно, что он демонстрирует поведение, которое вы описываете.

2 голосов
/ 02 ноября 2010

это из-за структуры памяти структуры. Ints прямо после друг друга. так что помещение структуры в вызове printf - это в основном то же самое, что и размещение каждого из них один за другим

1 голос
/ 02 ноября 2010

printf () имеет подпись "(char *, ...)".Это означает, что функция «printf» должна обрабатывать все аргументы после «char *».

Вы передаете структуру A в printf ().В памяти он имеет следующую раскладку: «int, int, int».Функция printf () читает строку формата («% d% d% d») и «думает», что вы передали ей 3 целых числа.И это «предположение» совпадает с макетом структуры.Поэтому он печатает все свои поля как отдельные значения.

Попробуйте удалить поле "b", и вы увидите, что printf () будет печатать значения поля "a", поля "c" и НЕИСПРАВНОСТЬ СЕГМЕНТАЦИИ .

...