Форум программистов, компьютерный форум CyberForum.ru

Visual C++

Войти
Регистрация
Восстановить пароль
 
 
Paulie
Айхрень...
306 / 174 / 4
Регистрация: 02.06.2009
Сообщений: 1,078
#1

Использование #pragma pack(push,1)... pack(pop) - Visual C++

27.11.2009, 11:58. Просмотров 39192. Ответов 51
Метки нет (Все метки)

Добрый день, товарищи.

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

C++
1
2
3
#pragma pack (push, 1)
deftype struct {...}
#pragma pack ( pop)
Но почему-то автор не рекомендует использовать, вот я не совсем понял этот момент. Он описал как-то расплывчато пример, когда это не сработает...

Я использую структуру с уже определёнными размерами параметров, так что её размер не будет меняться во времени, проверил, у меня всё работает.

Но почему же автор всё-таки не рекомендует это использовать???
Может есть ещё интересные варианты?

Для записи в файл использую CreateFile, WriteFile (MSDN->System services->File services->file systems->file management)...

Заранее благодарю.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.11.2009, 11:58     Использование #pragma pack(push,1)... pack(pop)
Посмотрите здесь:

Visual C++ что такое #pragma once?
Visual C++ Использование CIPAddressCtr
Visual C++ использование интерфейса из C# в C++
Visual C++ Использование Cuda
CDHtmlDialog использование Visual C++
Visual C++ Использование .DLL
#pragma Visual C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
programina
1913 / 598 / 37
Регистрация: 23.10.2011
Сообщений: 4,468
Записей в блоге: 2
29.05.2012, 17:20     Использование #pragma pack(push,1)... pack(pop) #41
Заменила все long'и на int'ы и теперь работает в 64-битном Минте, мб такое прокатит и в 32-битной системе
Вот небольшая программа превращающая превращает обычный рисунок в негатив
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdio.h>
 
#pragma pack(push,1)
struct BITMAPFILEHEADER {
    unsigned short  bfType;
    unsigned int    bfSize;
    unsigned short  bfReserved1;
    unsigned short  bfReserved2;
    unsigned int    bfOffBits;
};
#pragma pack(pop)
 
 
#pragma pack(push,1)
struct BITMAPINFOHEADER {
    unsigned int    biSize;
    unsigned int    biWidth;
    unsigned int    biHeight;
    unsigned short  biPlanes;
    unsigned short  biBitCount;
    unsigned int    biCompression;
    unsigned int    biSizeImage;
    unsigned int    biXPelsPerMeter;
    unsigned int    biYPelsPerMeter;
    unsigned int    biClrUsed;
    unsigned int    biClrImportant;
};
#pragma pack(pop)
 
 
#pragma pack(push,1)
struct PIXEL {
    unsigned char    b;
    unsigned char    g;
    unsigned char    r;
};
#pragma pack(pop)
 
 
 
int main()
{
    BITMAPFILEHEADER    fileheader;
    BITMAPINFOHEADER    infoheader;
    PIXEL               pixel;
    FILE                *fin, *fou;
 
    fin = fopen("picture1.bmp","rb+");
    fou = fopen("picture2.bmp","wb+");
 
    fread( &fileheader, sizeof(BITMAPFILEHEADER), 1, fin );
    fread( &infoheader, sizeof(BITMAPINFOHEADER), 1, fin );
 
    fwrite( &fileheader, sizeof(BITMAPFILEHEADER), 1, fou );
    fwrite( &infoheader, sizeof(BITMAPINFOHEADER), 1, fou );
 
    for (int i = 0; i < infoheader.biWidth*infoheader.biHeight; i+=1)
    {
        fread( &pixel, sizeof(PIXEL), 1, fin );
        pixel.b = 255 - pixel.b;
        pixel.g = 255 - pixel.g;
        pixel.r = 255 - pixel.r;
        fwrite( &pixel, sizeof(PIXEL), 1, fou );
    }
    fclose(fin);
    fclose(fou);
    return 0;
}
Миниатюры
Использование #pragma pack(push,1)... pack(pop)   Использование #pragma pack(push,1)... pack(pop)  
Evg
Эксперт CАвтор FAQ
17264 / 5518 / 342
Регистрация: 30.03.2009
Сообщений: 15,020
Записей в блоге: 26
29.05.2012, 17:36     Использование #pragma pack(push,1)... pack(pop) #42
Цитата Сообщение от programina Посмотреть сообщение
мб такое прокатит и в 32-битной системе
Прокатит. Но не прокатит на big endian машинах типа sparc'а (где порядок байтов в слове обратный)

И более аккуратно было бы делать что-то типа:

C
1
2
3
4
5
6
7
8
9
10
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
 
struct BITMAPFILEHEADER {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
};
Ну и так далее. С тем, чтобы если что-то надо поменять, то меняются только две строчки, а не миллион
programina
1913 / 598 / 37
Регистрация: 23.10.2011
Сообщений: 4,468
Записей в блоге: 2
29.05.2012, 18:01     Использование #pragma pack(push,1)... pack(pop) #43
Цитата Сообщение от Evg Посмотреть сообщение
C
1
2
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
Работает. Теперь буду делать только так.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1286 / 1220 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.05.2012, 10:57     Использование #pragma pack(push,1)... pack(pop) #44
Цитата Сообщение от programina Посмотреть сообщение
превращает обычный рисунок в негатив
У тебя не правильные структуры: Высота может быть отрицательной.
Ну и в начале нужна проверка, что это 24 битная картинка.
BBatonB
1 / 1 / 0
Регистрация: 19.07.2013
Сообщений: 21
26.07.2013, 00:01     Использование #pragma pack(push,1)... pack(pop) #45
Добавлю 3 комейки.
Еще не докопавшись до #pragma pack, решил, что (поскольку типы данных - ряд факториала) просто надо составлять структуры, помещая вверх самые объемные типы... и вниз по убывающей. А в конце ставить "пустой" член структуры, дополняющий размер структуры до размера, кратного размеру наибольшего типа.
В редких случаях, когда структура состит всего из двух членов, один из которых имеет тип максимального размера, а другой - минимального, "потери" памяти будут ощутимы.(реальных программ, в которых это может сказаться - еще меньше)
В большинстве же случаев они будут ничтожны. Зато хорошая скорость и гарантия не столкнуться с одной проблемой.

А вот застраховаться от различия в размере типов данных в разных... ситуациях - получается нельзя? - Это жаль. Разве что завести себе за правило всегда проверять типы при переходе на новое место?

Добавлено через 23 минуты
Только не "ряд факториала", а геом.прогрессия

Добавлено через 10 минут
А лучше всего было бы выбирать размер типов данных самому... из некоторого набора.
А может это возможно?
SatanaXIII
Супер-модератор
Эксперт С++
5578 / 2612 / 239
Регистрация: 01.11.2011
Сообщений: 6,422
Завершенные тесты: 1
02.12.2015, 13:34     Использование #pragma pack(push,1)... pack(pop) #46
Используя пример Evg
C++
#pragma pack (push, X)
struct
{
  char f1;
  int f2;
  short f3;
};
#pragma pack (pop)
нарисовал свою любимую священную всеобъясняющую картинку:

Использование #pragma pack(push,1)... pack(pop)

Использовать push с цифрой восемь и более, в данном примере, не имеет смысла потому, что размер наибольшего элемента структуры - int (четыре байта) меньше, чем эти параметры. И автоматом будет приводиться по наибольшему элементу структуры.
dvkobzev
0 / 0 / 0
Регистрация: 23.12.2016
Сообщений: 4
23.12.2016, 11:51     Использование #pragma pack(push,1)... pack(pop) #47
Спасибо Evg за пример с #pragma pack. Долго искал эту ценную информацию.
Моя задача в том, чтобы данные разной длины из структуры отправить байт за байтом. Для этого я хочу использовать одну и ту же часть памяти и как структуру с данными разной длины и как массив с ячейками по 8 бит.
То есть мне это нужно для того, чтобы из структуры с данными разной длины быстро получить массив данных по 8 бит.
Для этого важно, чтобы данные в структуре расположились в памяти без пробелов.
я создам 8-ми битный массив и наложу на него структуру. Благодаря #pragma pack (push, 1) данные структуры будут расположены в памяти без пробелов.

Вопрос: А байтовый массив может оказаться расположен в памяти с пробелами? Как я понял на эксперименте - нет. Да и по логике.

Вот пример как наложить структуру на массив (обращаться к массиву как к структуре):
C
1
2
3
4
5
6
7
8
9
10
/* [url]http://learnc.info/c/structures.html[/url]
Привести массив к структуре (или любому другому типу) по стандарту также
невозможно (хотя в различных компиляторах есть для этого инструменты).
Но в си возможно всё.
Но запомните, что в данном случае поведение не определено. -???
*/
    struct Point_t point1 = {10, 20};
    int x[3] = {300, 400, 500};
    point1 = (*(struct Point_t*)(x)); // волшебная строка
    printf("a = %d, b = %d", point1.x, point1.y);//структура выводит содержание массива
Кто знает - что означает звёздочка после типа: struct Point_t* ?

А как наоборот - наложить массив на структуру (обращаться к структуре как к массиву)?

Добавлено через 43 минуты
А как наоборот - наложить массив на структуру (обращаться к структуре как к массиву)? Нашёл ответ сам:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/* ************************** */
/* как наложить массив на структуру, точнее взять данные структуры как из 8-ми битного массива: */
 
// пример взят отсюда: [url]http://dml.compkaluga.ru/forum/index.php?showtopic=102963[/url]
// пример с #pragma pack (push, 1) взят отсюда: [url]http://www.cyberforum.ru/visual-cpp/thread67902.html[/url]
/* Создать тип структуры, данные которой располагаются в памяти без пробелов */
#pragma pack (push, 1)
struct xx {
uint8_t a;
uint8_t b;
uint32_t c;
};
#pragma pack (pop)
 
/* Объявим указатель на нашу структуру */
struct xx *xx_ptr;
 
/* и выделим под нее участок памяти */
xx_ptr = malloc(sizeof(struct xx));
 
/* Запишем что нибудь в нашу структуру */
xx_ptr->a = 0xAA;
xx_ptr->b = 0xBB;
xx_ptr->c = 0x12345678;
 
/* Заведем еще один - байтовый указатель, возьмем адрес нашей структуры
и пройдемся по ней, распечатывая каждый байт */
uint8_t *byte_ptr; //создать байтовый указатель
byte_ptr = (uint8_t *) xx_ptr; //поместить в указатель адрес структуры
int i=0;
while(i < sizeof(struct xx)) {
printf("[%04d] %02X\n", i, *(byte_ptr+i)); //вывод структуры побайтно
++i;
}
Evg
Эксперт CАвтор FAQ
17264 / 5518 / 342
Регистрация: 30.03.2009
Сообщений: 15,020
Записей в блоге: 26
23.12.2016, 13:26     Использование #pragma pack(push,1)... pack(pop) #48
Цитата Сообщение от dvkobzev Посмотреть сообщение
Вопрос: А байтовый массив может оказаться расположен в памяти с пробелами? Как я понял на эксперименте - нет. Да и по логике
Не может (если я вопрос понял правильно)

Цитата Сообщение от dvkobzev Посмотреть сообщение
Кто знает - что означает звёздочка после типа: struct Point_t* ?
Звёздочка означает указатель. С такими вопросами обычно отправляют читать учебники
dvkobzev
0 / 0 / 0
Регистрация: 23.12.2016
Сообщений: 4
23.12.2016, 14:42     Использование #pragma pack(push,1)... pack(pop) #49
В учебниках я не нашёл почему звёздочка то до названия, то после названия:
point1 = (*(struct Point_t*)(x));
Как расшифровывается эта строка? point1 - это указатель типа "struct Point_t" , а дальше..?
Evg
Эксперт CАвтор FAQ
17264 / 5518 / 342
Регистрация: 30.03.2009
Сообщений: 15,020
Записей в блоге: 26
23.12.2016, 15:05     Использование #pragma pack(push,1)... pack(pop) #50
преобразовать "x" к типу "struct Point_t*", а потом разыменовать (самая первая звёздочка)
dvkobzev
0 / 0 / 0
Регистрация: 23.12.2016
Сообщений: 4
23.12.2016, 17:05     Использование #pragma pack(push,1)... pack(pop) #51
Цитата Сообщение от Evg Посмотреть сообщение
к типу "struct Point_t*"
тип struct Point_t - это понятно:
C
1
2
3
4
struct Point_t {
    int x;
    int y;
};
Так было бы понятно:
struct Point_t *xx_ptr; //xx_ptr-указатель на структуру

Но что такое тип struct Point_t* ?

Добавлено через 18 минут
Понял: тип struct Point_t* - это "Указатель типа struct Point_t"

Вот простой пример:

void *p; // Указатель обобщенного типа
int *a; // Указатель на целое число
a = (int*) p; // Указатель а пусть станет равным указателю р после его приведения к типу "Указатель на целое число"

Взято от сюда: http://www.intuit.ru/studies/courses...re/1974?page=7
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.12.2016, 21:03     Использование #pragma pack(push,1)... pack(pop)
Еще ссылки по теме:

использование CFormView Visual C++
Visual C++ Использование DLL C++ в C#
Visual C++ Использование WFA в C++
Использование DLL Visual C++
Visual C++ Pragma comment()

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Evg
Эксперт CАвтор FAQ
17264 / 5518 / 342
Регистрация: 30.03.2009
Сообщений: 15,020
Записей в блоге: 26
23.12.2016, 21:03     Использование #pragma pack(push,1)... pack(pop) #52
У тебя уже набралось 3 поста, по идее ты уже можешь темы создавать. Создай себе по одной теме на каждый интересующий тебя вопрос. В теме про упаковку структур ты всё равно не найдёшь желающих обучать тебя базовым основам из учебника
Yandex
Объявления
23.12.2016, 21:03     Использование #pragma pack(push,1)... pack(pop)
Ответ Создать тему
Опции темы

Текущее время: 20:58. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru