1. ## Си / Говнокод #25372

1. 01
2. 02
3. 03
4. 04
5. 05
6. 06
7. 07
8. 08
9. 09
10. 10
11. 11
12. 12
13. 13
14. 14
15. 15
16. 16
17. 17
18. 18
19. 19
20. 20
21. 21
22. 22
23. 23
24. 24
25. 25
26. 26
27. 27
28. 28
29. 29
30. 30
31. 31
32. 32
33. 33
34. 34
35. 35
36. 36
37. 37
38. 38
39. 39
40. 40
41. 41
42. 42
43. 43
``````// http://p99.gforge.inria.fr/p99-html/group__flexible.html

//C99 allows a flexible array member to be defined as the last member of a struct,
// namely an array of undetermined length.

char name[20];
size_t len;
uint64_t data[];
};

// Such a struct can then be allocated on the heap with a suitable size such
// that the field data has as many elements as fit in the allocated space from
// the start of data onward. Usually one would allocate such struct with

package_head *b = malloc(sizeof(*b) + 12 * sizeof(b->data[0]));

// This has several disadvantages. Firstly, the syntax is clumsy. We have to
// use a relatively complicated expression that uses two elements of the specification of a or b.

// Secondly, it wastes space. Due to packing of the struct the offset of data "inside"
//  the struct may be less than sizeof(package_head). In most cases the real size
// of the object that we want to construct is

offsetof(package_head, data) + N * sizeof(uint64_t)

// so we are wasting

// bytes.

// The above formula for the exact size is only valid for larger values of N. We must
// also ensure that we allocate at least sizeof(package_head) bytes. So the complete
// formula looks something like

#define P99_FSIZEOF(T, F, N) P99_MAXOF(sizeof(T), offsetof(T, F) + P99_SIZEOF(T, F[0]) * N)

// which is probably not something that you want to write on a daily basis.

// We provide several interfaces to allocate struct with flexible members``````

Херню написали какую-то. Забыли самое главное : нельзя так в лоб аллоцировать память под структуры. Потому что выравнивание может не то быть.
Надо использовать http://man7.org/linux/man-pages/man3/aligned_alloc.3.html

• Кстати, почему есть aligned_alloc, но нет aligned_realloc?
Ответить
• Только какая-то виндоспецифичная хрень нагуглилась
``https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-realloc?view=vs-2017``
Ответить
• И aligned_free нету.
Ответить
• Я в какой-то библиотеке для «Трубопаскакаля» видел самодельные aligned_alloc, aligned_realloc, aligned_free. Там всё было сделано через жопу ООП: память выделялась средствами стандартной библиотеки, оригинальный указатель сохранялся в приватном поле объекта (чтобы можно было делать realloc и free), а функция aligned_alloc возвращала выровненный указатель.
Ответить
• А можно было просто возвращать выровненный указатель, только еще выделять место для хранения исходного перед выровненным блоком (ну или один байт смещения).
Ответить
• A previous call to free or realloc that deallocates a region of memory synchronizes-with a call to aligned_alloc that allocates the same or a part of the same region of memory. This synchronization occurs after any access to the memory by the deallocating function and before any access to the memory by aligned_alloc. There is a single total order of all allocation and deallocation functions operating on each particular region of memory.

Т.е. realloc не дурак.
Ответить
• Демоническая память нинужна.
Ответить
• Емнип, по стандарту и обычный malloc достаточно ровный для всех примитивов. Для SSE разве что может не хватить.
Ответить
• https://en.cppreference.com/w/c/memory/aligned_alloc
> Regular malloc aligns memory suitable for any object type (which, in practice, means that it is aligned to alignof(max_align_t)). This function is useful for over-aligned allocations, such as to SSE, cache line, or VM page boundary.
Ответить
• Мне интересно, если я молокой выделю, например, байт, то вся память от этого бата до следующего выровненного адреса зашкварится и молока её никому не отдаст при следующих выделениях?
Ответить
• Если для мелочи нет отдельных пулов - да, зашкварится.
Ответить
• Ну не совсем вся, я тут методом тыка выяснил, что перед блоком памяти нужно ещё поместить 8 батй с размером этого блока, а если места недостаточно, то памяти зашкварится больше –— до 2-го выделанного адреса.

Именно поэтому я за сатаническую память.
Ответить
• > 8
На 64-битке вроде даже 16 тратится под это.
Ответить
• Не, я проверил:
на 32 битах: 16 байт выравнивание, перед блоком 4 байта с размером занятого блока + 1 (или | 1 ? наверное это флажок занят/свободен), размер блока кратен 16;
на 64: та же хуйня, но размеры в джва раза больше.

Кстати, а есть целочисленный тип, который для любой платформы будет размером с указатель?
Ответить
• uintptr_t

Странно, что всего одно число. Как они из такого списка потом удаляют? Не пробегать же всю кучу по порядку.
Ответить
• Хм, мне пакозалось, что для free достаточно:
``````void free(void *p)
{
((uintptr_t*)p)[-1] &= ~1;
}``````
Но второй малок этот блок не отдал.
Ответить
• У тебя всё зафрагментируется к хуям от такой реализации... Нужно мёржить свободные блоки.
Ответить
• По идее там должно быть 2 числа, примерно как в джвусвязном списке. Проверь.
Ответить
• Я проверил, я малеха наврал про выравнивание, но поле там одно:
``https://tio.run/##[email protected]/z2mj6oOodZdnZ2GDG/[email protected]@[email protected]@[email protected]@fubBdC0z6ume6WAGOIOfUuMyvL47topqq30n9mZN8wE``
Ответить
• Кстати, а имеет ли право маллок юзать плотные пулы для мелочи?

Если у меня структура весит 5 байт, то в ней может таиться dword, т.е. начало должно быть выровнено хотя бы на 4?
Ответить
• 10 это размер data?
``````struct package_head {
char name[20]; //20 байт
size_t len; //8 байт
uint64_t data[]; //8 байт (флексанутый массив же размером 1?)
};``````

20 + 8 + 8 + 10 = 46, и правда не очень выровнено

В VC нету никаких "Flexible Arrays" (потому что нету С99, а есть ли они в С++ я не знаю) именно потому я за "Microsoft"
Ответить
• > флексанутый массив же размером 1?
Мне кажецца что нуль должно быть, не зря же можно ещё и huint64_t data[0]. Но гцц молчит как пармизан:
``error: invalid application of ‘sizeof’ to incomplete type ‘struct petux’``
Ответить
• Надо так:
``````#include <stdio.h>
int main() {
struct Kooryatnik { int petux; int kooritsy[]; } kooryatnik;
printf("%d", sizeof(kooryatnik)); // 4, проверь
}``````
значится, что 0
Ответить