Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/104: Рейтинг темы: голосов - 104, средняя оценка - 4.62
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
1

Выравнивание адреса памяти

21.10.2016, 14:48. Показов 20834. Ответов 47
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Прочитал на разных ресурсах про выравнивание адреса данных, но многое ещё не понятно.

Чего я понял:
Выравнивание адреса нужно для того что бы снизить количество обращений процессором к памяти для считывания хранимых данных
Чем больше объем данных адрес которых нуждается в выравнивании, тем больше усилий процессор прилагает что бы получить данные по невыровненному адресу
Не все процессоры умеют выравнивать адрес памяти самостоятельно

Чего я не понял:
Увидел следующее утчерждение: Адрес данных должен быть кратен размеру считываемых данных. Как программист может повлиять на кратность адреса, если выделением адреса данных занимается компилятор и этот процесс насколько понимаю выходит за пределы программного кода?
Некоторые компиляторы сами занимаются выравниванием адресов(дополняя данные адреса нулями) что бы можно было считать блок данных за минимальное количество обращений процессором к памяти. Именно не понятно, зачем забивать данные нулями

Прошу помочь разобраться

Добавлено через 17 минут
И ещё не ясно что приводит к "кривости" памяти которую потом приходится выравнивать

Добавлено через 52 минуты
Пока бродил по инету, нашел пример где структура с одинаковыми полями занимает разный объем в памяти в зависимости от последовательности типов в структуре.
Это тоже как то связано с выравниванием данных?
http://rextester.com/WLM62012 24 байта
http://rextester.com/UKWSN11327 16 байта

Добавлено через 11 минут
Кажется начал понимать почему заполняются нулями данные. Похоже дело в том, что каждый процессор может прочитать только определенное количество данных за одно обращение к памяти. Допустим, это число равно 4. Когда процессор читает char, нельзя позволить что бы он прочитал 1 байт который относится к char и 3 байта от других данных. Поэтому к char будут добавлены нули, что бы свести общий размер данных к 4. Если это так, то почему char a = 'b'; printf("%zu", sizeof(a)); равно 1, а не 4? В то время как внутри структуры из примера выше заполнение нулями есть(это определил потому что размер структуры превышает тот размер которого достаточно для хранения его данных)

Добавлено через 13 минут
Цитата Сообщение от sys_beginner Посмотреть сообщение
то время как внутри структуры из примера выше заполнение нулями есть
Выходит о выравнивании данных нужно заботиться только в том случае, когда в непрерывной области памяти находятся данные разных типов? Как например структуры, или массив функций которые возвращают значения разного типа? (Массив функций возвращаемое значение которых есть указатель на void*)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.10.2016, 14:48
Ответы с готовыми решениями:

Выделить в памяти 1024 ячейки по 8 байт и вывести их адреса(МИНИ менеджер памяти))
Вот тут появилась такая интересная задача: требуется сделать программу которая управляет 1024...

Записать дополнительный код содержимого 16 ячеек памяти, начиная с адреса 910. Результаты занести в ячейки памяти, н
Записать дополнительный код содержимого 16 ячеек памяти, начиная с адреса 910. Результаты занести в...

Выравнивание памяти под 16
Hello, всем привет! Хочу выровнять массив НОРМАЛЬНО, чтобы вместо movups юзать movaps, что в...

Выравнивание памяти в stm32
Соственно сабж Нигде не найду как организована память. В документации по этому поводу нашел...

47
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
21.10.2016, 14:59 2
Цитата Сообщение от sys_beginner Посмотреть сообщение
Как программист может повлиять на кратность адреса, если выделением адреса данных занимается компилятор и этот процесс насколько понимаю выходит за пределы программного кода?
Не всегда. Если у вас есть некий объем байт в виде unsigned char* то, чтобы корректно прочитать/записать по некоторому адресу из него, скажем, double, нужно чтобы этот некоторый адрес был выровнен по границе double (т.е. кратен его размеру). Под "корректно" следует понимать "без сбоев/крэшей" ибо, в системах где есть контроль этого дела все может пойти под откос при несоблюдении.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 15:01  [ТС] 3
Если я прав, то что интересует ответ на вопрос, как именно нужно выравнивать данные? С помощью перестановки последовательности типов как я сделал выше в двух ссылках на rextester?
Во втором случае объем занимаемой памяти под те же самые данные как видим уменьшился. Или есть ещё другие способы?

Добавлено через 2 минуты
Цитата Сообщение от HighPredator Посмотреть сообщение
ужно чтобы этот некоторый адрес был выровнен по границе double
А как обеспечить кратность этого самого адреса? Как выравнивать?
0
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
21.10.2016, 15:05 4
Цитата Сообщение от sys_beginner Посмотреть сообщение
А как обеспечить кратность этого самого адреса? Как выравнивать?
Вот в этом посте есть пример (в первом цикле) Заменить функцию strlen на свою
Там для лонгворда сделано, но принцип тот же
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 15:11  [ТС] 5
Цитата Сообщение от sys_beginner Посмотреть сообщение
А как обеспечить кратность этого самого адреса? Как выравнивать?
Допоню вопрос: почему именно кратным, а не "не кратным"? Это связано с тем, что процессоры в зависимости от модели за одно обращение к памяти читают данные четным количеством байт? Например по 2, 4, 6 или 8 и т.д?

Добавлено через 5 минут
Цитата Сообщение от HighPredator Посмотреть сообщение
(в первом цикле)
Спасибо за пример но не очень понял где там выравнивание и зачем оно там нужно. Данные в char* ведь распологаются непрерывно, чем хуже вариант просто пройтись по индексам строки считая количество элементов пока не встретится \0?
0
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
21.10.2016, 15:18 6
Sizeof структуры
0
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
21.10.2016, 15:25 7
Цитата Сообщение от sys_beginner Посмотреть сообщение
не очень понял где там выравнивание
Там же даже комментарии есть...
C
1
2
3
4
5
6
7
8
9
10
11
/* Handle the first few characters by reading one character at a time.
     Do this until CHAR_PTR is aligned on a longword boundary.  */
  for (char_ptr = str; ((unsigned long int) char_ptr & (sizeof (longword) - 1)) != 0;
       ++char_ptr)
    if (*char_ptr == '\0')
      return char_ptr - str;
 
  /* All these elucidatory comments refer to 4-byte longwords,
     but the theory applies equally well to 8-byte longwords.  */
 
  longword_ptr = (unsigned long int *) char_ptr;
Игнорируйте возврат, смотрите ниже. Вообще этот цикл что делает? Выравнивает указатель по границе лонгворда. Зачем? Чтобы дальше данные можно было пользовать как лонгворд через указатель на лонгворд.
0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 15:34  [ТС] 8
Цитата Сообщение от gazlan Посмотреть сообщение
In addition the data structure as a whole may be padded with a final unnamed member. This allows each member of an array of structures to be properly aligned.
То есть кроме заполнения нулями данных полей когда это необходимо, при необходимости и в конец структуры тоже добавляются выравнивающие нули?

Цитата Сообщение от HighPredator Посмотреть сообщение
Игнорируйте возврат, смотрите ниже. Вообще этот цикл что делает? Выравнивает указатель по границе лонгворда. Зачем? Чтобы дальше данные можно было пользовать как лонгворд через указатель на лонгворд.
По границе лонгворда это означает, что будут взяты уже существующие данные, записаны в лонгворд, а все свободные ячейки лонгворда будут забиты нулями?
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 15:43 9
Цитата Сообщение от sys_beginner Посмотреть сообщение
То есть кроме заполнения нулями данных полей когда это необходимо, при необходимости и в конец структуры тоже добавляются выравнивающие нули?
sys_beginner, ну откуда ты взял, что эти "дыры" там кто-то обязан заполнять нулями?
Это ведь потеря времени.
2
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 15:46  [ТС] 10
Цитата Сообщение от Убежденный Посмотреть сообщение
Это ведь потеря времени.
Значит просто резервируется дополнительное место где лежит мусор?
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 15:48 11
Да. Я просто хотел бы отметить, что забивать эту память нулями не обязательно.
2
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
21.10.2016, 15:57 12
Цитата Сообщение от sys_beginner Посмотреть сообщение
По границе лонгворда это означает, что будут взяты уже существующие данные, записаны в лонгворд, а все свободные ячейки лонгворда будут забиты нулями?
Изобразил схематично как мог, с адресами:
Код
Buffer:
+----+----+----+----+----+----+----+----+
|0xAA|0xAB|0xAC|0xA1|0xB2|0xC3|0xD4|....| 
+----+----+----+----+----+----+----+----+
  ^^
@ 0xFFAA01 (start_ptr)

Aligning: for (ptr = start_ptr; ((unsigned long int) ptr & (sizeof (longword) - 1)) != 0; ++ptr)
+----+----+----+----+----+----+----+----+
|0xAA|0xAB|0xAC|0xA1|0xB2|0xC3|0xD4|....| 
+----+----+----+----+----+----+----+----+
                 ^^
@ 0xFFAA04 (ptr aligned)

Reading longword from aligned ptr:
longword l = *ptr;
+----+----+----+----+----+----+      +----+----+----+----+
|....|0xA1|0xB2|0xC3|0xD4|....| -->  |0xA1|0xB2|0xC3|0xD4|
+----+----+----+----+----+----+      +----+----+----+----+
       ^^
ptr @ 0xFFAA04                           longword l now has value of 0xA1B2C3D4
2
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 16:13  [ТС] 13
Убежденный,
Понял. Спасибо!

Как я понял, выравнивание сводится к следующему:
Если нужно переменную малого типа привести к переменной большего типа(например int к long), тогда результат занимает 4 байта а остальные 4 забиваются мусором, что бы сократить количество обращений процессором к памяти для считывания данных. Если этот процесс можно вычислить на этапе компиляции, то данную работу берет на себя компилятор. Если же дело происходит в рантайме, то разработчик сам должен заполнить оставшуюся часть памяти большего типа мусором что бы обеспечить выравнивание. Я правильно понимаю?

Если данные разных типов, находящиеся в одном непрерывном блоке памяти(например, в структуре) не соблюдают правильную последовательность определения типов, то данные заполняются компилятором с помощью мусора. То есть правильно писать struct {char a; char b; int n;} а не {char a; int b; char b;}. Но почему так происходит я не понимаю. Можете кто нибудь объяснить?
По идее оба char-a должны быть забиты до 4 байта (1 байт сам char и 3 байта мусора) на 32 битных системах, а на 64 битных должно быть 7 байт мусора на каждый char в структуре?

Добавлено через 8 минут
Именно не понятно почему тут http://rextester.com/WLM62012 24 байта. Тут http://rextester.com/UKWSN11327 понимаю почему 16 байтов, по 4 байта выровненные char-ы и 8 long.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 16:54 14
1. Приведение переменных разных типов и размеров друг к другу не имеют
никакого отношения к выравниванию данных и выполняется по правилам
языка C или C++.

2. Тип размером в byte не требует выравнивания; word - должен быть выравнен,
как минимум, по границе 2 байт; dword - 4 байт; qword - 8 байт и т.д.

3. Выравнивание и размеры структур зависят от опций компилятора,
например #pragma pack в MS C++ Compiler.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 16:58  [ТС] 15
Цитата Сообщение от Убежденный Посмотреть сообщение
Тип byte не требует выравнивания
А разве есть такой тип byte? Или имеется ввиду char?
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 17:01 16
Это условно, чтобы не отвлекаться на типы из C/C++, которые на
разных платформах и компиляторах могут иметь разные размеры.
А так byte - 1 байт, word - 2 байта, dword - 4 байта, qword - 8 байт.
0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 17:22  [ТС] 17
Цитата Сообщение от Убежденный Посмотреть сообщение
Выравнивание и размеры структур зависят от опций компилятора,
например #pragma pack
Встречал опцию которая запрещает выравнивание.

Поговорили много, но честно говоря до сих пор не представляю себе общую картину.

В целом хочу знать все о выравнивании. Из конкретных вопросов пока для меня актуальны следующие:
1. В каких случаях применять выравнивание
2. Как именно нужно выполнять выравнивание, что для этого нужно делать. Можно просто в теории. Словами. Что бы я понял идею
3. В каких случаях и как выравнивание применяет сам компилятор (чем руководствуется? опции? какие значения по умолчанию?)
4. Как выравнивать данные что бы код был переносимым между 32 и 64 битными ОС

Естественно если у кого то есть дополнительная информация буду рад если поделитесь. Просто другие вопросы у меня пока не созрели

Добавлено через 1 минуту
Цитата Сообщение от Убежденный Посмотреть сообщение
Тип размером в byte не требует выравнивания;
А почему тогда по второй ссылке на rextester поля char вроде как увеличился до 4 байт каждый? (Исходя из общего размера структуры)
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 20:25 18
sys_beginner, мне кажется, тут какое-то чрезмерно повышенное внимание к выравниванию.

В 99% случаев тебе вообще об этом не нужно беспокоиться, так как всю работу выполняет
компилятор и аллокатор памяти.

Выравнивание нужно, потому что процессору "легче" работать с выравненными данными.
Поэтому если нет каких-то "противопоказаний", то компилятор делает так, чтобы и код, и
данные были выравнены наиболее оптимальным образом. Например, переменная char в
стеке может храниться как dword, т.е. 4 байта, потому что так удобнее, а перерасход
памяти минимальный. Все создаваемые стековые объекты также размещаются компилятором по
выравненному адресу. Кстати, в Win64 очень строгие требования к выравниванию -
стековый кадр должен быть выравнен по границе 16 байт. И компилятор в режиме x64
это обеспечивает. А мы-то и не знаем, да?

На некоторых архитектурах доступ к невыравненным данным приводит к исключению.

На x86/x64 правильное выравнивание данных является одной из гарантией того, что
доступ к таким данным будет атомарен (для некоторых базовых типов).

Некоторые инструкции, например SSE, требуют особого выравнивания, для этого
существуют такие вещи, как _aligned_malloc (MS C/C++ Compiler).

Для переносимости данных, например структур, между разными платформами и
компиляторами также применяются единые для всех настройки выравнивания.

Иногда вместо #pragma pack "дырки" в структурах заполняют вручную, создавая
дополнительные поля с именами типа "Padding".

Вот, пожалуй, и все.
4
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.10.2016, 20:44  [ТС] 19
Цитата Сообщение от Убежденный Посмотреть сообщение
В 99% случаев тебе вообще об этом не нужно беспокоиться, так как всю работу выполняет
компилятор и аллокатор памяти.
Вот очень хочется хорошо понимать этот 1% Во всех случаях которые я откопал в поисковике всё сводится просто к порядку расположения переменных в зависимости от типа.

Кстати, насчет padding-а. Я понял зачем он нужен и где он располагается(перед объявлением/определением) переменной тип которого отличается от char. Делается это автоматически компилятором что бы такая переменная начиналась с адреса который делился бы на количество байт этой переменной(которая не char) а точнее на количество байт требуемое для хранения её типа, например для short это будет 2 без остатка. Причины этого тоже понятны.

Но никак не могу понять когда пишут определенный код что бы выравнить данные на уровне самого кода. Почему компилятор это не сделал за программиста? Почему malloc не решил вопрос выравнивания как ты упомянул, а это пришлось сделать программисту.
Мне интересно, в каких случаях требуется вмешательство программиста и как он может эффективно выровнить данные. Что он должен делать и как узнать что настал именно тот момент, когда выравнивать нужно самому?
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
21.10.2016, 21:29 20
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но никак не могу понять когда пишут определенный код что бы выравнить данные на уровне самого кода. Почему компилятор это не сделал за программиста? Почему malloc не решил вопрос выравнивания как ты упомянул, а это пришлось сделать программисту.
А откуда malloc знает, какое нам требуется выравнивание?
А вдруг нам надо выравнивать данные или код по границе в 4096 байт?
0
21.10.2016, 21:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.10.2016, 21:29
Помогаю со студенческими работами здесь

Выравнивание сегмента памяти
Дано задание:Захватить один кусок памяти размером N Кбайт. Заполнить его нулями. Захватить другой...

Выравнивание памяти и скорость работы.
Есть ли преимущество использования переменных длинной в 4 байта в 32 битных процессорах ARM в...

Адреса памяти
Здравствуйте, столкнулся с проблемой. Не могу понять, каким образом находятся адреса памяти...

Узнать адреса памяти
Всем привет! Не знал в какой теме разместить, разместил тут. Как узнать адреса памяти? Тоесть...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru