[C] как разместить структуру внутри буфера
От: B0FEE664  
Дата: 27.02.19 09:40
Оценка:
Как на C написать placement new для различных структур?

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

typedef struct
{
 ...
} MyStruct;

typedef struct
{
  const char* begin;
  const char* end;
  const char* tail;
} Buffer;

MyStruct* Create_MyStruct(Buffer* pBuffer)
{
  if ( NULL == pBuffer )
    return NULL;

  if ( pBuffer->end < pBuffer->tail + sizeof(MyStruct) )
    return NULL;

  MyStruct* pNewObj = (MyStruct*)pBuffer->tail;
  pBuffer->tail += sizeof(MyStruct);  // _Alignof(MyStruct) ?

  return pNewObj;
}
И каждый день — без права на ошибку...
Re: [C] как разместить структуру внутри буфера
От: kov_serg Россия  
Дата: 27.02.19 10:37
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Допустим у меня есть предзаказанный буфер длиною N и я хочу внутри него разместить несколько разных экземпляров разных структур. Как это сделать правильно?



BFE> pBuffer->tail += sizeof(MyStruct); // _Alignof(MyStruct) ?

У вас размер структуры должен быть выравнен (paddings). Достаточно что бы начало вашего региона было выравнено.
А так можете вручную выравнивать если память линейная
#define align(x,n) ((char*)(x)+(-(int)(char*)(x)&(n-1)))
Отредактировано 27.02.2019 10:42 kov_serg . Предыдущая версия .
Re[2]: [C] как разместить структуру внутри буфера
От: B0FEE664  
Дата: 27.02.19 10:54
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>Допустим у меня есть предзаказанный буфер длиною N и я хочу внутри него разместить несколько разных экземпляров разных структур. Как это сделать правильно?

BFE>> pBuffer->tail += sizeof(MyStruct); // _Alignof(MyStruct) ?
_>У вас размер структуры должен быть выравнен (paddings).
Зачем мне выравнивать размер структуры? Структуры разные и разного размера должны лежать в одном буфере. Выравнивать все по одному размеру — зря расходовать память.

_>Достаточно что бы начало вашего региона было выравнено.

разве?

_>А так можете вручную выравнивать если память линейная

Память линейная, но я не понимаю как это применять:
_>
_>#define align(x,n) ((char*)(x)+(-(int)(char*)(x)&(n-1)))
_>
И каждый день — без права на ошибку...
Re: [C] как разместить структуру внутри буфера
От: Mihas  
Дата: 27.02.19 11:14
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:


BFE>Допустим у меня есть предзаказанный буфер длиною N и я хочу внутри него разместить несколько разных экземпляров разных структур. Как это сделать правильно?

Уж, не union ли тебе нужен? Или я чего не понимаю?
Отредактировано 27.02.2019 11:15 Mihas . Предыдущая версия .
Re[3]: [C] как разместить структуру внутри буфера
От: Sergey_BG Россия  
Дата: 27.02.19 11:18
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>разве?

Я прочитал что такое alignof и увидел, что оно возвращает что задаёт alignas. А последнее это аналог pragma pack. Т.е. Для структуры он задаёт выравнивание полей по некоторому размеру.
Т.е. размер струтуры от этого меняется, так как меняется положение полей внутри структуры. И для массива одинаковых структур, вам достаточно выравнять положение первого элемента массива. sizeof вернёт размер кратный выравниванию. И следующая структура будет тоже выравнена. Для разных структур, надо выравнивать каждую структуру.
Сергей
Отредактировано 27.02.2019 12:11 Sergey_BG . Предыдущая версия .
Re: [C] как разместить структуру внутри буфера
От: watchmaker  
Дата: 27.02.19 11:53
Оценка: 4 (1)
Здравствуйте, B0FEE664, Вы писали:


BFE>Допустим у меня есть предзаказанный буфер длиною N и я хочу внутри него разместить несколько разных экземпляров разных структур. Как это сделать правильно?


Твой вариант в общем-то норм, но в нём будет проблема с выравниванием.

Если есть структуры struct S1 { char data; } и struct S4 { int data; }, то вызов Create_S1(), за которым следует Create_S4(), приведёт к тому, что поля второй структуры будут неверно выровнены (при допущении, что sizeof(int) > 1 и при естественном допущении, что изначально буфер был выровнен, например, из-за того, что был получен вызовом malloc).

То есть необходимо перед "выделением" памяти проверять значение tail и довыравнивать его при необходимости.
Например, как-то так:
uintptr_t uiTail = (uintptr_t)(pBuffer->tail);
uiTail = (uiTail + (_Alignof(MyStruct) - 1)) / _Alignof(MyStruct) * _Alignof(MyStruct); // тут педанты могут ещё проверить на переполнение
char* tail = (сhar*)uiTail; // теперь дальше нужно использовать этот tail вместо (pBuffer->tail)

if ( pBuffer->end < tail + sizeof(MyStruct) ) // тут формально тоже может быть переполнение, на которое можно проверить
    return NULL;


MyStruct* pNewObj = (MyStruct*)tail;

pBuffer->tail = (char*)(pNewObj + 1);


BFE>typedef struct

BFE>{
BFE> const char* begin;
BFE> const char* end;
BFE> const char* tail;
BFE>} Buffer;
Занимательно, что функция выделения памяти хранить указатели на const, а выдаёт наружу указатели без const. Интересно, из каких соображений этот const в Buffer появился?
Отредактировано 27.02.2019 16:55 watchmaker . Предыдущая версия .
Re[2]: [C] как разместить структуру внутри буфера
От: B0FEE664  
Дата: 27.02.19 14:18
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>Допустим у меня есть предзаказанный буфер длиною N и я хочу внутри него разместить несколько разных экземпляров разных структур. Как это сделать правильно?

W>Твой вариант в общем-то норм, но в нём будет проблема с выравниванием.
Собственно, в правильном выравнивании и состоит вопрос.

W>Если есть структуры struct S1 { char data; } и struct S4 { int data; }, то вызов Create_S1(), за которым следует Create_S4(), приведёт к тому, что поля второй структуры будут неверно выровнены (при допущении, что sizeof(int) > 1 и при естественном допущении, что изначально буфер был выровнен, например, из-за того, что был получен вызовом malloc).

W>То есть необходимо перед "выделением" памяти проверять значение tail и довыравнивать его при необходимости.
Я так и думал. Правильно ли я понимаю, что адрес структуры должен быть кратным _Alignof(имя структуры)?
как-то так:
MyStruct* Create_JsnToken(Buffer* pBuffer)
{
  if ( NULL == pBuffer )
    return NULL;

  const int nPadding = (pBuffer->tail - (char*)NULL) % _Alignof(MyStruct);

  if ( pBuffer->end < pBuffer->tail + nPadding + sizeof(MyStruct) )
    return NULL;

  pBuffer->tail += nPadding;

  MyStruct* pNewObj = (MyStruct*)pBuffer->tail;
  pBuffer->tail += sizeof(MyStruct);  

  return pNewObj;
}


  тут что-то странное
W>Например, как-то так:
W>
W>uintptr_t uiTail = (uintptr_t)(pBuffer->tail);

W>uiTail = (uiTail + (_Alignof(MyStruct) - 1)) % _Alignof(MyStruct); // тут педанты могут ещё проверить на переполнение
// ] uiTail == 20 and _Alignof(MyStruct) == 4 then uiTail == 3 ?

W>char* tail = (сhar*)uiTail; // теперь дальше нужно использовать этот tail вместо (pBuffer->tail)
// char* tail = pBuffer->tail + (сhar*)uiTail; ?

W>if ( pBuffer->end < tail + sizeof(MyStruct) ) // тут формально тоже может быть переполнение, на которое можно проверить
W>    return NULL;

W>MyStruct* pNewObj = (MyStruct*)tail;

W>pBuffer->tail = (char*)(pNewObj + 1); // +1 ? Чего-то я не понимаю... 
W>


W>Занимательно, что функция выделения памяти хранить указатели на const, а выдаёт наружу указатели без const. Интересно, из каких соображений этот const в Buffer появился?

Этот код из головы.
И каждый день — без права на ошибку...
Re[3]: [C] как разместить структуру внутри буфера
От: kov_serg Россия  
Дата: 27.02.19 15:44
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Зачем мне выравнивать размер структуры? Структуры разные и разного размера должны лежать в одном буфере. Выравнивать все по одному размеру — зря расходовать память.

Выравнивают не для экономии памяти, а для уменьшения количества обращений к памяти (которая читается в кэш блоками). Так что не заморачивайтесь и выравнивайте например по 16 байт все свои разные структуры.

_>>Достаточно что бы начало вашего региона было выравнено.

BFE>разве?
У вас была всего одна структура. И если она кратна 4 байтам и выравнивание у вас 4 байта, то это будет сохраняться.

_>>А так можете вручную выравнивать если память линейная

BFE>Память линейная, но я не понимаю как это применять:
_>>
_>>#define align(x,n) ((char*)(x)+(-(int)(char*)(x)&(n-1)))
_>>

   struct A { ... };
   enum { sizeof_A4=(sizeof(struct A)+3)&~3 };
   enum { sizeof_A8=(sizeof(struct A)+7)&~7 };
   enum { sizeof_A16=(sizeof(struct A)+15)&~15 };
   ...
   char *x=0; int dx=123, dxa=dx, a=8;
   x+=dx;
   x=x+(-(int)x&(a-1))); // выравниваем на 8
   x=align(x,a);         // тоже самое - выравниваем на 8
   dxa=(dxa+a-1)&(a-1);  // выравниваем размер на 8
   x+=dxa;               // выравнивание сохраняется
Re[3]: [C] как разместить структуру внутри буфера
От: watchmaker  
Дата: 27.02.19 15:47
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE> Правильно ли я понимаю, что адрес структуры должен быть кратным _Alignof(имя структуры)?

Да.

BFE>как-то так:

BFE>const int nPadding = (pBuffer->tail — (char*)NULL) % _Alignof(MyStruct);
Нет, тут неверно.
Re[3]: [C] как разместить структуру внутри буфера
От: andrey.desman  
Дата: 27.02.19 15:58
Оценка: 1 (1) +1
Здравствуйте, B0FEE664, Вы писали:

BFE>
BFE>MyStruct* Create_JsnToken(Buffer* pBuffer)
BFE>{
//Это то, на сколько указатель из размера выравнивания выбивается, а не сколько надо добавить, чтобы стать кратным _Alignof(MyStruct).
BFE>  const int nPadding = (pBuffer->tail - (char*)NULL) % _Alignof(MyStruct);
BFE>  if ( pBuffer->end < pBuffer->tail + nPadding + sizeof(MyStruct) )
BFE>
Re[3]: [C] как разместить структуру внутри буфера
От: Mr.Delphist  
Дата: 28.02.19 09:35
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Зачем мне выравнивать размер структуры? Структуры разные и разного размера должны лежать в одном буфере. Выравнивать все по одному размеру — зря расходовать память.

В ряде случаев, выравнивание увеличивает эффективность обмена между памятью и процессором. Ещё в ряде случаев, процессор просто пошлёт программиста читать маны при первой же попытке обратиться к невыровненным данным.
Re[4]: [C] как разместить структуру внутри буфера
От: B0FEE664  
Дата: 01.03.19 09:20
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>>>
_>   x=x+(-(int)x&(a-1))); // выравниваем на 8
_>

А разве представление отрицательных чисел в дополнительном коде гарантируется стандартом C?
И каждый день — без права на ошибку...
Re[5]: [C] как разместить структуру внутри буфера
От: kov_serg Россия  
Дата: 01.03.19 10:35
Оценка:
Здравствуйте, B0FEE664, Вы писали:
_>>>>
_>>   x=x+(-(int)x&(a-1))); // выравниваем на 8
_>>

BFE>А разве представление отрицательных чисел в дополнительном коде гарантируется стандартом C?
Вам шашечки или ехать?
Re[6]: [C] как разместить структуру внутри буфера
От: B0FEE664  
Дата: 01.03.19 12:09
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>А разве представление отрицательных чисел в дополнительном коде гарантируется стандартом C?

_>Вам шашечки или ехать?

шашечки.
И каждый день — без права на ошибку...
Re[5]: [C] как разместить структуру внутри буфера
От: _NN_ www.nemerleweb.com
Дата: 03.03.19 10:13
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, kov_serg, Вы писали:


_>>>>
_>>   x=x+(-(int)x&(a-1))); // выравниваем на 8
_>>

BFE>А разве представление отрицательных чисел в дополнительном коде гарантируется стандартом C?

Скоро будет
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: [C] как разместить структуру внутри буфера
От: watchmaker  
Дата: 03.03.19 10:51
Оценка: +1
Здравствуйте, _NN_, Вы писали:

BFE>>А разве представление отрицательных чисел в дополнительном коде гарантируется стандартом C?


_NN>Скоро будет


Твоя ссылка про другой язык — не про C.
Re[6]: [C] как разместить структуру внутри буфера
От: kov_serg Россия  
Дата: 03.03.19 11:09
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Скоро будет

Вот не очень понятно чем модульная арифметика им не угодила.
Видимо очень хотят новых граблей в виде a+b+c != a+c+b и других прелестей.
Re[7]: [C] как разместить структуру внутри буфера
От: watchmaker  
Дата: 03.03.19 11:21
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Вот не очень понятно чем модульная арифметика им не угодила.

Ну написали же:

over 90% of all overflow is a bug, and defining wrapping behavior would not have solved the bug.

и пару других причин.

И сделав переполнение определённым ты лишишь санитайзеры возможности находить ошибки в коде: в исходниках ведь не написано для каждой арифметической операции является ли переполнение в ней желаемым поведением или программист просто забыл его проверить.
Re[7]: [C] как разместить структуру внутри буфера
От: _NN_ www.nemerleweb.com
Дата: 03.03.19 11:39
Оценка: +1
Здравствуйте, watchmaker, Вы писали:

_NN>>Скоро будет


W>Твоя ссылка про другой язык — не про C.


Ну да, там C++..
На данный момент С11 позволяет выбрать одну из 3-х реализаций.
Возможно в C сдадутся
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: [C] как разместить структуру внутри буфера
От: kov_serg Россия  
Дата: 03.03.19 14:43
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, kov_serg, Вы писали:


_>>Вот не очень понятно чем модульная арифметика им не угодила.

W>Ну написали же:
W>

over 90% of all overflow is a bug, and defining wrapping behavior would not have solved the bug.

W>и пару других причин.

W>И сделав переполнение определённым ты лишишь санитайзеры возможности находить ошибки в коде: в исходниках ведь не написано для каждой арифметической операции является ли переполнение в ней желаемым поведением или программист просто забыл его проверить.


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