Программирование >>  Перегруженные имена функций и идентификаторы 

1 ... 125 126 127 [ 128 ] 129 130 131 ... 210


#pragma pack(1) struct { /* ... */ }; #pragma pack(4)

Последняя директива #pragma pack(4) служит для того, чтобы вернуться к более раннему значению выравнивания. В принципе, конечно же при написании исходного текста никогда доподлинно заранее неизвестно, какое же было значение выравнивания до его смены, поэтому в некоторых компиляторах под Win32 есть возможность использования стека значений (пошло это из MS Visual C++):

#pragma pack(push, 1)

struct { /* ... */ };

#pragma pack(pop)

В примере выше сначала сохраняется текущее значение выравнивания, затем оно заменяется 1, затем восстанавливается ранее сохраненное значение. При этом, подобный синтаксис поддерживает даже gcc для Win32 (еще стоит заметить, что, вроде, он же под Unix использовать такую запись #pragma pack не дает). Есть альтернативная форма #pragma pack(), поддерживаемая многими компиляторами (включая msvc и gcc), которая устанавливает значение выравнивания по умолчанию.

И, тем не менее, это не хорошо. Опять же, это дает очень интересные ошибки. Представим себе следующую организацию исходного текста. Сначала заголовочный файл inc.h:

#ifndef inc h

#define inc h

class Object

...

#endif inc h

Представьте себе, что существуют три файла filel.cpp, file2.cpp и file2.h, которые этот хидер используют. Допустим, что в file2.h находится функция foo, которая (например) записывает Object в файл:

file1.cpp #include inc.h



#include file2.h int main()

Object* obj = new Object(); foo(obj, file );

delete obj;

return 0;

file2.h

#ifndef file2 h #define file2 h

#pragma pack(1)

#include inc.h

void foo(const Object* obj, const char* fname); #pragma pack(4) #endif file2 h

file2.cpp #include file2.h

void foo(const Object* obj, const char* fname)

...

Это все скомпилируется, но работать не будет. Почему? Потому что в двух разных единицах компиляции (filel.cpp и file2.cpp) используется разное выравнивание для одних и тех же структур данных (в данном случае, для объектов класса Object). Это даст то, что объект переданный по указателю в функцию foo() из функции main() будет разным (и, конечно же, совсем неправдоподобным). Понятно, что это явный пример плохой организации исходнтх текстов - использование директив



компилятора при включении заголовочных файлов, но, поверьте, он существует.

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

На самом деле #pragma pack не является панацеей. Мало того, использование этой директивы практически всегда неправомерно. Можно даже сказать, что эта директива в принципе редко когда нужна (во всяком случае, при прикладном программировании).

Правильным же подходом является сначала записать все поля структуры в нужном порядке в некоторый буфер и скидывать в файл уже содержимое буфера. Это очень просто и очень эффективно, потому что все операции чтения/записи можно собрать в подпрограммы и менять их при необходимости таким образом, чтобы обеспечить нормальную работу с внешними файлами. Проиллюстрируем этот подход:

template<class T>

inline size t get size(const T& obj)

return sizeof(obj);

Эта функция возвращает размер, необходимый для записи объекта. Зачем она понадобилась? Во-первых, возможен вариант, что sizeof возвращает размер не в байтах, а в каких-то собственных единицах. Во-вторых, и это значительно более необходимо, объекты, для которых вычисляется размер, могут быть не настолько простыми, как int. Например:

template<>

inline size t get size<std::string>(const std::string& s)

return s.length() + 1;

Надеемся, понятно, почему выше нельзя было использовать sizeof.



1 ... 125 126 127 [ 128 ] 129 130 131 ... 210

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика