Перейти к содержанию
    

Указатель на невыровненную память

On 10/19/2023 at 8:56 AM, Arlleex said:

Вы щас серьезно?😆 А как быть с тем, что уже сделано предыдущим поколение разработчиков, причем, буквально повсюду?

По хорошему, переделать.

Но если нравится работа сапера (хотя скорее ассенизатора), то можно оставить как есть

Да, бывает, что лучше его (код, а вы что подумали) палочкой не ковырять. Чтоб не воняло.

Пусть кто-нибудь другой вляпается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#ifndef UNALIGNED_H__
#define UNALIGNED_H__

template<typename T>
struct unaligned
{
    operator T() const                  { return Data; }
    void operator =(T const & value)    { Data = value; }

    T   Data;
} __attribute__((packed));


#endif  // UNALIGNED_H__

Объявить данные как unaligned<uint16_t>, unaligned<int32_t>, unaligned<что угодно> и делать с ними что угодно. В том числе и работать с указателями на unaligned<что угодно>. Но это плюсы, да.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/19/2023 at 9:55 AM, MrYuran said:

По хорошему, переделать.

Но если нравится работа сапера (хотя скорее ассенизатора), то можно оставить как есть

А как быть с протоколами Ethernet и всем тем, что работает поверх него ?

А с Modbus ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/19/2023 at 10:01 AM, dimka76 said:

А как быть с протоколами Ethernet и всем тем, что работает поверх него ?

А с Modbus ?

А что с ними не так? Модбас так по умолчанию имеет регистры uint16_t, выравнивай-не хочу. а входной поток сливается в байтовый буфер и затем парсится в какой-нибудь uint16_t InputRegisters[NumOf]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

55 минут назад, MrYuran сказал:

А что с ними не так? Модбас так по умолчанию имеет регистры uint16_t, выравнивай-не хочу. а входной поток сливается в байтовый буфер и затем парсится в какой-нибудь uint16_t InputRegisters[NumOf]

Ну так то в Modbus не все 16-битное: slave ID, код функции и т.д. - байтовые. И структуру "подгонять" под данные не получится.

В Ethernet, да и вообще в любых интерфейсах и протоколах (не только сетевых) сериализация и упаковка данных имеет важное значение: скорость передачи и детерминированность при взаимодействии различных архитектур.

Как раз костыльный способ - это пытаться натянуть на некий набор упорядоченных данных какую-то там структуру, чтобы в ней не было паддингов для какой-то конкретной архитекруры CPU.
 

1 час назад, Сергей Борщ сказал:

Но это плюсы, да.

А что делать Си-шникам? Получается, в GCC нет специального ключевого слова для обозначения невыровненного доступа?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

56 minutes ago, MrYuran said:

Модбас так по умолчанию имеет регистры uint16_t, выравнивай-не хочу

Нифига подобного. Есть команды работы с битовыми объектами, есть работа с файлами. Там идёт работа именно с байтами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/19/2023 at 11:07 AM, Arlleex said:

Как раз костыльный способ - это пытаться натянуть на некий набор упорядоченных данных какую-то там структуру, чтобы в ней не было паддингов для какой-то конкретной архитекруры CPU.

А мапить структуру на фрейм - вообще последнее дело.

Сугубо мое личное мнение, основанное на печальном опыте

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, MrYuran сказал:

Вообще нормальная практика предполагает все-таки выравнивание в структурах.

Я бы рад, да не от меня зависит. Когда это пакет данных, передаваемый по какому либо интерфейсу - приходится подстраиваться.
А защитить себя хочется.

14 часов назад, arhiv6 сказал:

В cmsis_gcc.h есть макрос __UNALIGNED_UINT32(x) :

Интересное решение, правда не совсем то, что я хотел, но если его немного развить то получается следующее:

//Упакованная структура
struct Foo {
	uint8_t v1 = 1;
	uint16_t v2 = 2;
	const uint16_t v3 = 3;
	struct {
		int v4;
	} bar;
} __attribute__((packed));
Foo foo;

//Вспомогательный класс
template<typename T>
struct Unaligned {
	struct Packed {
		Packed() = default;
		Packed &operator = (const T &value) {v = value; return *this;}
		operator T () const {return v;}
//		T *operator ->() {return &v;}
//		const T *operator ->() const {return &v;}
	protected:
		T v;
	} __attribute__((packed));
	constexpr Unaligned(T *ptr): ptr((Packed*)ptr) {}
	Packed &operator * () const {return *ptr;}
	Packed &operator ->() const {return *ptr;}
	Packed &operator [](unsigned index) const {return ptr[index];}
protected:
	Packed *ptr;
};

//Функция создания объекта Unaligned
template<typename T>
auto unaligned(T *ptr) {return Unaligned<T>(ptr);}

//Функция принимающая unaligned указатель
void func(Unaligned<uint16_t> array) {
	array[0] = 40;
}

//Пример использования
auto vPtr = unaligned(&foo.v2); //создание unaligned указателя
v = *vPtr + vPtr[0]; //Чтение данных по указателю или элемента массива

//Запись различными способами
*vPtr = 10; 
vPtr[0] = 20;
*unaligned(&foo.v2) = 30;

//Попытка записать в константу
*unaligned(&foo.v3) = 40; //error: assignment of read-only member 'Unaligned<const short unsigned int>::Packed::v'

//А вот это пока не могу решить
unaligned(&foo.bar)->v4 = 50;

//Передача невыровненного указателя в функцию
typedef void (*Func)(Unaligned<uint16_t> array);
Func f = &func;
f(&foo.v2);

 

Теперь появляется следующий вопрос, как побороться с предупреждением компилятора при вызове конструктора?
warning: taking address of packed member of 'Foo' may result in an unaligned pointer value [-Waddress-of-packed-member]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 минут назад, MrYuran сказал:

А мапить структуру на фрейм - вообще последнее дело.

Почему?

Для Ethernet - это самый оптимальный путь. Да и для USB частенько.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, MrYuran сказал:

А мапить структуру на фрейм - вообще последнее дело.

Вполне себе нормальное решение, которое подойдет абсолютно всем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Arlleex said:
2 hours ago, Сергей Борщ said:

 Но это плюсы, да.

А что делать Си-шникам?

точно так же заворачивать memcpy в макросы 🙂

2 hours ago, dimka76 said:

А как быть с протоколами Ethernet

не пытаться запихивать сетевые протоколы в упакованые структуры

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, _pv сказал:

не пытаться запихивать сетевые протоколы в упакованые структуры

Ваше предложение?

Они уже туда запихнуты RFC. Как предлагаете это решать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 минут назад, Ivan. сказал:

Теперь появляется следующий вопрос, как побороться с предупреждением компилятора при вызове конструктора?
warning: taking address of packed member of 'Foo' may result in an unaligned pointer value [-Waddress-of-packed-member]

Так значит пришли к тому, от чего уходили - т.е. не решили вопрос, а лишь дописали кучу плюсовых наворотов:vava:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, Arlleex сказал:

Так значит пришли к тому, от чего уходили - т.е. не решили вопрос, а лишь дописали кучу плюсовых наворотов

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

А во вторых я так и сказал, что это не совсем то, но интересная идея

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Ivan. сказал:

А во вторых я так и сказал, что это не совсем то, но интересная идея

Осталось только посмотреть: в какой код выливается эта "интересная идея"? А то может оказаться (по факту) совсем не интересной...  :wink:

 

Без всяких плюсов должно работать тривиальное:

#pragma pack(push, 1)
struct PackU64 {
  u64 d64;
};
#pragma pack(pop)
struct Qqq {
  u8 x1;
  PackU64 x2;
};
Qqq volatile qqq;

u32 volatile z;

void F1(void volatile *p)
{
  u64 q = ((PackU64 volatile *)p)->d64;
  z = q;
  z = q >> 32;
}

int main()
{
  z = qqq.x1;
  F1((void volatile *)&qqq.x2);
  return 0;
}

Проверяем - компилим "gcc 9.2.1 20191025". Получаем:

  20                _Z2F1PVv:
  21                  .fnstart
  22                .LFB0:
  23                  @ args = 0, pretend = 0, frame = 0
  24                  @ frame_needed = 0, uses_anonymous_args = 0
  25                  @ link register save eliminated.
  26 0000 0168        ldr r1, [r0]  @ unaligned
  27 0002 024B        ldr r3, .L2
  28 0004 4268        ldr r2, [r0, #4]  @ unaligned
  29 0006 1960        str r1, [r3]
  30 0008 1A60        str r2, [r3]
  31 000a 7047        bx  lr

Т.е. - всё ок: для чтения qqq.x2 использованы команды, допускающие невыровненные обращения (2шт. LDR).

 

Для проверки комментируем строки:

//#pragma pack(push, 1)
...
//#pragma pack(pop)

Компилим, получаем:

  20                _Z2F1PVv:
  21                  .fnstart
  22                .LFB0:
  23                  @ args = 0, pretend = 0, frame = 0
  24                  @ frame_needed = 0, uses_anonymous_args = 0
  25                  @ link register save eliminated.
  26 0000 D0E90001    ldrd  r0, [r0]
  27 0004 014B        ldr r3, .L2
  28 0006 1860        str r0, [r3]
  29 0008 1960        str r1, [r3]
  30 000a 7047        bx  lr

И убеждаемся, что метод работает: Для чтения qqq.x2 теперь компилятор использовал LDRD (так как он считает, что qqq.x2 выровнена).

Как видно - никаких варнингов (при взятии указателя) нет. Всё как хотел ТС. И без всяких ненужных плюсовых наворотов.  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...