__declspec(align(1)) struct MyStruct {
T value; // !!! T — произвольный простой тип (int, char*, pointer и т.д.)
U another_value; // !!! U — тоже простой произвольный тип, может отличаться от T
};
Здравствуйте, Аноним, Вы писали:
А>Копирующий конструктор при вызове sprintf не вызывается(?), т.к. понятия не имеет о типе (см. сигнатуру sprintf)...
Вообще-то передача объектов в функцию с переменным числом параметров UB, но конкретно майкрософтовский компилятор делает так.
Он кладёт копии объектов в стек, а потом их разрушает.
Например, можно печатать, как строчку CString, потому, что внутри CString есть только одно поле, которое является указателем на строку (все служебные поля, вроде длины, числа владельцев и т. п. в MFC'ишной строке лежат перед буфером, в котором лежит строка)
А>P.S. Да, не хочется делать явное приведение!!!
А>Подскажите как лучше сделать?
Лучше всего объяснить зачем тебе это понадобилось и на каком языке ты пишешь...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Вообще-то передача объектов в функцию с переменным числом параметров UB, но конкретно майкрософтовский компилятор делает так. E>Он кладёт копии объектов в стек, а потом их разрушает. E>Например, можно печатать, как строчку CString, потому, что внутри CString есть только одно поле, которое является указателем на строку (все служебные поля, вроде длины, числа владельцев и т. п. в MFC'ишной строке лежат перед буфером, в котором лежит строка)
А>>P.S. Да, не хочется делать явное приведение!!!
А>>Подскажите как лучше сделать?
E>Лучше всего объяснить зачем тебе это понадобилось и на каком языке ты пишешь...
А лучше всего конкретно указывать то что ты хочешь:
sprintf(szBuf, "%d", s.value);
А>__declspec(align(1)) struct MyStruct {
А> T value; // !!! T - произвольный простой тип (int, char*, pointer и т.д.)
А> U another_value; // !!! U - тоже простой произвольный тип, может отличаться от T
А>};
А>MyStruct s;
А>...
А>sprintf(szBuf, "%d", s); // или
А>sprintf(szBuf, "%X", s);
А>Вот так вот хотелось бы!!! Т.е. если например T unsigned short, то вывести 2 байта...
В общем виде (не специально заточенном под конкретную платформу) фокус не выйдет.
Дело в том, что,
1) Когда ты передаёшь аргументы-числа, компилятор расширяет их до int, long, long long (если это целые) и double, long double (если это вещественные).
Поэтому short всегда представлен как int. И printf об этом знает, и может как-то учитывать при переводе из двоичного числа в строку.
А в структуре short представлен как short, и что там в оставшихся двух байтах — неизвестно. (С точки зрения printf — там мусор).
Причём если платформа big endian, то value окажется в старшей (якобы ненужной) части int, а младшая часть int совпадёт со старшей частью another_value.
2) Даже если ты укажешь выравнивание структуры такое же, как у элементов стека, — всё равно зазоры структуры будут заполнены мусором.
Ну а цена трюков может оказаться сравнимой с ценой явной передачи элементов структуры.
Скажем
printf(fmt, s);
// то же самое, что
printf(fmt, s.value, s.another_value);
(разумеется, только в том случае, когда стек растёт в сторону убывания адресов).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: sprintf()
От:
Аноним
Дата:
27.09.07 09:56
Оценка:
Да понятно что можно указывать прям мембер...
Здравствуйте, ajanov, Вы писали:
A>Здравствуйте, Erop, Вы писали:
E>>Вообще-то передача объектов в функцию с переменным числом параметров UB, но конкретно майкрософтовский компилятор делает так. E>>Он кладёт копии объектов в стек, а потом их разрушает. E>>Например, можно печатать, как строчку CString, потому, что внутри CString есть только одно поле, которое является указателем на строку (все служебные поля, вроде длины, числа владельцев и т. п. в MFC'ишной строке лежат перед буфером, в котором лежит строка)
А>>>P.S. Да, не хочется делать явное приведение!!!
А>>>Подскажите как лучше сделать?
E>>Лучше всего объяснить зачем тебе это понадобилось и на каком языке ты пишешь... A>А лучше всего конкретно указывать то что ты хочешь: A>sprintf(szBuf, "%d", s.value);
Re[2]: sprintf()
От:
Аноним
Дата:
27.09.07 10:08
Оценка:
Спасибо большое! Думаю, затея не оправдывает себя...
Еще раз спасибо за подробное разъяснение!
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, <Аноним>, Вы писали:
К>
А>>__declspec(align(1)) struct MyStruct {
А>> T value; // !!! T - произвольный простой тип (int, char*, pointer и т.д.)
А>> U another_value; // !!! U - тоже простой произвольный тип, может отличаться от T
А>>};
А>>MyStruct s;
А>>...
А>>sprintf(szBuf, "%d", s); // или
А>>sprintf(szBuf, "%X", s);
К>
А>>Вот так вот хотелось бы!!! Т.е. если например T unsigned short, то вывести 2 байта...
К>В общем виде (не специально заточенном под конкретную платформу) фокус не выйдет. К>Дело в том, что,
К>1) Когда ты передаёшь аргументы-числа, компилятор расширяет их до int, long, long long (если это целые) и double, long double (если это вещественные). К>Поэтому short всегда представлен как int. И printf об этом знает, и может как-то учитывать при переводе из двоичного числа в строку. К>А в структуре short представлен как short, и что там в оставшихся двух байтах — неизвестно. (С точки зрения printf — там мусор).
К>Причём если платформа big endian, то value окажется в старшей (якобы ненужной) части int, а младшая часть int совпадёт со старшей частью another_value.
К>2) Даже если ты укажешь выравнивание структуры такое же, как у элементов стека, — всё равно зазоры структуры будут заполнены мусором.
К>Ну а цена трюков может оказаться сравнимой с ценой явной передачи элементов структуры. К>Скажем К>
К>// traits по определению подходящего типа
К>template<class T> struct stacked { typedef T type; };
К>template<> struct stacked<char> { typedef int type; };
К>template<> struct stacked<short> { typedef int type; };
К>template<> struct stacked<signed char> { typedef int type; };
К>template<> struct stacked<unsigned char> { typedef unsigned int type; };
К>template<> struct stacked<unsigned short> { typedef unsigned int type; };
К>template<> struct stacked<float> { typedef double type; };
К>template<class T, class U>
К>__declspec(align(1)) struct MyStruct
К>{
К> typename stacked<T>::type value;
К> typename stacked<U>::type another_value;
К>};
К>
К>В этом случае можно понадеяться, что К>
К>printf(fmt, s);
К>// то же самое, что
К>printf(fmt, s.value, s.another_value);
К>
К>(разумеется, только в том случае, когда стек растёт в сторону убывания адресов).