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

    −1

    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.
    //P99_DECLARE_STRUCT(package_head);
    
    struct package_head {
      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 *a = malloc(sizeof(package_head) + 10 * sizeof(uint64_t));
    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
    
    sizeof(package_head) - offsetof(package_head, data)
    
    // 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

    Запостил: j123123, 12 Февраля 2019

    Комментарии (25) RSS

    • Кстати, почему есть 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/##VU7LCsIwELznK5aKkLYqKuil1R@xIiWJutAmJdmKD/z2mj6oOodZdnZ2GDG/CNE0E9SiqKWCFDXRo1Jucd2zr1rmRWHEv@ZIomkl5n@gzFHzm0EZshcDj6omxwOHT5VRLqVVzh3mq@O4BGHS@c7GAm8TEHawTPxId7DdJBDHGEKf1aL2norsiSAaEryfj2oUQl@S4xDclbD@fubBdC0z6ume6WAGOIOfUuMyvL47topqq30n9mZN8wE
                        Ответить
        • Кстати, а имеет ли право маллок юзать плотные пулы для мелочи?

          Если у меня структура весит 5 байт, то в ней может таиться dword, т.е. начало должно быть выровнено хотя бы на 4?
          Ответить
    • показать все, что скрытоvanished
      Ответить
      • > флексанутый массив же размером 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
          Ответить

    Добавить комментарий