|
Ламерской вопрос, массив unsigned char |
|
|
|
 |
Ответов
(15 - 29)
|
Feb 8 2007, 15:51
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
"Массив char в физической памяти будет лежать так, как на это указывает #pragma pack, то бишь выравнивание, если 4, то каждый элемент массива будет расположен с адреса, кратного 4, то есть занимать 4 байта." Давайте оставим впокое физическую память, будем говорить про память, адресуемую по скажем [R0] и пусть сама эта память лежит где хочет. Так вот я утверждаю, что при инкременте R0 на единицу мы получаем доступ к следущему элементу массива. И никакие прагмы паки тут совершенно роли не играют. Не так ? pragma pack является директивой выравнивания структур, она не имеет отношения к массивам. По крайней мере в части их размещения
|
|
|
|
|
Feb 8 2007, 16:30
|

Знающий
   
Группа: Свой
Сообщений: 648
Регистрация: 11-02-06
Из: Санкт-Петербург
Пользователь №: 14 237

|
Цитата(DASM @ Feb 8 2007, 15:51)  "Массив char в физической памяти будет лежать так, как на это указывает #pragma pack, то бишь выравнивание, если 4, то каждый элемент массива будет расположен с адреса, кратного 4, то есть занимать 4 байта." Давайте оставим впокое физическую память, будем говорить про память, адресуемую по скажем [R0] и пусть сама эта память лежит где хочет. Так вот я утверждаю, что при инкременте R0 на единицу мы получаем доступ к следущему элементу массива. И никакие прагмы паки тут совершенно роли не играют. Не так ? pragma pack является директивой выравнивания структур, она не имеет отношения к массивам. По крайней мере в части их размещения Зависит от компилятора, размера элемента массива и установленного выравнивания !!! Если мы говорим о массиве char, размер элемента равен 1. Если мы установили выравнивание данных, равное 16, то, чтобы получить доступ к следующему элементу массива типа char, Вам в приведенном Вами примере придется увеличить R0 на 16. В части различия компиляторов -- часть компиляторов применяет #pragma pack только к структурам, при этом для остальных типов у них есть что-то типа #pragma data_align. Это непринципиально. И обсуждалось уже здесь
--------------------
Сделано в Китае. Упаковано в России.
|
|
|
|
|
Feb 8 2007, 17:02
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(Demeny @ Feb 8 2007, 16:56)  Вы оба неправы, господа. Этим занимается аппаратно контроллер памяти (неважно какой, SDRAM, SRAM, DDR) - все эти дела совершенно прозрачны для программиста и для процессора, исполняющего команды программиста.  ИМХО тут неправы Вы. Для программиста не так уж и всё прозрачно, если конечно он не на бейсике пишет. Цитата Обратите внимание - несмотря на то, что разрядность шины данных процессора увеличивается (от 8 битных 8088, далее через 16 битные 8086/80286, через 32 битные 80386/Pentium-ы, а теперь есть и 64 битные ...) - ПО КАЖДОМУ АДРЕСУ ПАМЯТИ ЛЕЖИТ РОВНО ОДИН БАЙТ !!! На некотором подмножестве из всех имеющихся платформ. Цитата С точки зрения любого процессора (и программиста) физическая память является линейной структурой байтов, адрес каждого байта уникален и отличается от адреса предыдущего и последующего ровно на единицу. Не всегда и не везде. Цитата 32 разрядный процессор "хочет" загрузить себе в регистр один байт из адреса 0x123456FF, и его совершенно не волнует, каким образом внешняя память "исполнит его желание". Более того, проц не обязан "знать", что за память расположена по этому адресу. Дальнейшие действия целиком и полностью возложены на контроллер памяти, который всё это "знает". Если память 32 разрядная - будет выполнено ДВА цикла чтения - один по адресу 0x123456FC, другой по адресу 0x12345700, а оставшиеся два младших бита в исходном адресе будут определять, как расположить считанные 8 байт на 32 разрядной шине так, чтобы процесоор "почувствовал", будто он и вправду считал двойное слово с адреса 0x123456FF. На x86 оно реализовано ради совместимости, на очень многих других платформах этого нет. А есть или исключения, или игнорирование младших битов (как в случае с ARM) К томуже в тех же x86-расширениях (типа MMX/SSE/SSEx) есть команды допускающие только обращение к выравненным данным. Цитата Хочется сэкономить память - указывай align=1, но тогда при доступе к 3 элементам из 4 будешь "попадать" по времени на ДВА цикла чтения; если памяти море - указывай align=4 (вроде как это по умолчанию), тогда каждый объект массива char будет лежать "как король" в адресах, кратных 4, чтобы не тратить лишнее время на доступ к нему. Применительно к char (на х86) чтение будет всегда одно. PS а архитектуры всякие бывают, не надо всех под гребёнку x86 причёсывать.
|
|
|
|
|
Feb 8 2007, 17:09
|

Знающий
   
Группа: Свой
Сообщений: 648
Регистрация: 11-02-06
Из: Санкт-Петербург
Пользователь №: 14 237

|
Цитата(DASM @ Feb 8 2007, 16:39)  И что ? Вы хотите сказать, что вашим шаманством я могу сделать такое - char data[256]; printf ("%d\r\n" (int) &data[1] - (int) &data[0]); и получить на экране 16 ? Сообщите пожалуйста такой удивительный компилятор и я посыплю голову пеплом RVDS на этот счет говорит ясно "There are no packed array types. A packed array is an array of objects of packed type. There is no padding in the array." Ага, я понял. Мы говорим о разных вещах. Вы в приведенном примере путаете УКАЗАТЕЛЬ на элемент и АДРЕС элемента в памяти. Это разные вещи. Операция & возвращает указатель на элемент, и результат будет равен 1. По сути, указатель - это всего лишь ИНДЕКС элемента в сегменте данных программы. Именно поэтому указатель всегда указывает на вполне ОПРЕДЕЛЁННЫЙ тип данных, чтобы компилятор мог правильным образом обслуживать арифметику указателей. Например, Код double * pDouble; double data[100]; pDouble = &(data[45]); pDouble = pDouble + 1; Вас же не удивляет такая операция - указатель увеличился на 1, а указывает уже на 46 элемент массива double (что говорит о том, что адрес сместился на 8). Если Вы отпечатаете pDouble, то увидите, что он действительно увеличился всего на 1. А изначально Ваш пример содержал регистр процессора R0, на уровне машинных кодов регистр косвенной адресации действительно увеличится на число, зависящее от размера элемента и от выравнивания данных. Чтобы не продолжать спор, я готов его завершить, если Вы мне скажете, как я могу разместить массив char data[200000] с адресов, кратных 4, чтобы не делать лишнюю работу контроллеру 32 разрядной памяти при доступе к каждому элементу? Если, по Вашему, невозможно применить выравнивание к массивам ...
--------------------
Сделано в Китае. Упаковано в России.
|
|
|
|
|
Feb 8 2007, 17:12
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
мы по прежнему друг друга не понимаем. Не можете. Можно указать что начальный адрес массивы будет с адреса кратного 4, но все char - ы в нем будут идти ПОСЛЕДОВАТЕЛЬНО и адрес последнего элемента будет N + (200000-1) Перефразирую так. Имеем линейную память. 0,1,2,3,4,5,6,7.... Вы можете вашими директивами расположить массив чаров так, что [0] лежал в 0-й ячейке, а [1] в 4-ой ячейке ? Я утверждаю что нет
|
|
|
|
|
Feb 8 2007, 17:23
|

Знающий
   
Группа: Свой
Сообщений: 648
Регистрация: 11-02-06
Из: Санкт-Петербург
Пользователь №: 14 237

|
Цитата(DASM @ Feb 8 2007, 17:12)  мы по прежнему друг друга не понимаем. Не можете. Можно указать что начальный адрес массивы будет с адреса кратного 4, но все char - ы в нем будут идти ПОСЛЕДОВАТЕЛЬНО и адрес последнего элемента будет N + (200000-1) Перефразирую так. Имеем линейную память. 0,1,2,3,4,5,6,7.... Вы можете вашими директивами расположить массив чаров так, что [0] лежал в 0-й ячейке, а [1] в 4-ой ячейке ? Я утверждаю что нет Как же , по Вашему, будут идти элементы массива, если размер каждого элемента равен 13, при установленном выравнивании (не важно какой директивой) 16?
--------------------
Сделано в Китае. Упаковано в России.
|
|
|
|
|
Feb 8 2007, 18:03
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 3-08-06
Пользователь №: 19 285

|
Цитата(DASM @ Feb 8 2007, 17:25)  через 13 байт. Слитно. Массива ! Будем продолжать спор, я пока что на RVDS и IAR проверил (вот дожил, очевидное проверять), и , естественно убедился, что в массиве структур никакого паддинга между элементами массива не будет А вы смотрели на расположение в ROM или после инициализации в RAM? Насколько я понимаю в RAM с выравниваем 4, паддинг будет.
|
|
|
|
|
Feb 8 2007, 19:22
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
По поводу игноригования младших битов адреса в ARM-е я пожалуй погорячился. Всё немного хитрее. хитрый пример (GCC и LPC2292) Код typedef struct __attribute__ ((__packed__)) { uchar uc; uint ui; } test_struct_t;
test_struct_t data[5] = { {'A', 0x00010203}, {'B', 0x04050607}, {'C', 0x08090A0B}, {'D', 0x0C0D0E0F}, {'E', 0x10111213} };
void test() { int n; uint* pui; uchar* puc;
printf("sizeof(test_struct_t)=%d\n", sizeof(test_struct_t)); printf("sizeof(data)=%d\n", sizeof(data)); printf("sizeof(data[0])=%d\n", sizeof(data[0]));
printf("Loop 1\n"); for(n=0; n<5; n++) { printf("%d: %c 0x%08X %p\n", n, data[n].uc, data[n].ui, &data[n].ui); }
printf("Loop 2\n"); for(n=0; n<5; n++) { pui = &data[n].ui; puc = &data[n].uc; printf("%d: %c 0x%08X %p\n", n, *puc, *pui, pui); } } Выдаёт: Код sizeof(test_struct_t)=5 sizeof(data)=25 sizeof(data[0])=5 А теперь угадайте что выдают на печать первый и второй циклы? Одно и тоже? Какбы не так: Код Loop 1 0: A 0x00010203 4000003d 1: B 0x04050607 40000042 2: C 0x08090A0B 40000047 3: D 0x0C0D0E0F 4000004c 4: E 0x10111213 40000051 Loop 2 0: A 0x41010203 4000003d 1: B 0x42000607 40000042 2: C 0x4304050B 40000047 3: D 0x0C0D0E0F 4000004c 4: E 0x45111213 40000051 В первом случае компилятор знает что элемент data[n].ui не (всегда) выровнен на границу слова, поэтому читает слово ЧЕТЫРМЯ!!! инструкциями ldrb, и из этих 4-х байт "собирает" слово. Во втором случае компилятор предполагает что pui - указатель на выровненное слово и читает сразу слово командой ldr. И вот тут вылазит особенности ARMа по работе с невыравненными данными. По сути младшие 2 бита адреса слова используются как количество байт на которое циклически сдвигается прочитанное слово. А с точки зрения голых Сей результат должен быть одинаковый. Т.ч. ИМХО программер должен много чего знать по части платформы, компилятора и т.д.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|