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

    +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
    #include <stdio.h>
    #include <stdlib.h>
    
    void myfree(void *ptr)
    {
      printf("%p\n", *(void **)ptr);
      free(*(void **)ptr);
      printf("freed!\n");
    }
    
    int main(void) {
      char *x __attribute__ (( cleanup (myfree)  )) = malloc(1);
      printf("%p\n", x);
      return 0;
    }

    https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html

    cleanup (cleanup_function)

    The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored.

    If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally.

    Запостил: j123123, 09 Апреля 2019

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

    • А еще есть __attribute__((constructor)) и __attribute__((destructor))
      https://stackoverflow.com/questions/2053029/how-exactly-does-attribute-constructor-work
      Ответить
    • *(void **)ptr
      Как это работает? Зачем разыменовывать void указатель?
      Ответить
      • Мы кастуем void * в void ** а потом разыменовываем. Это чтоб получить значение самого x а не указателя на него
        Ну т.е. в функцию void myfree(void *ptr) передается указатель на x. Можно переписать как-нибудь вот так:
        void myfree(char **ptr)
        {
          printf("%p\n", *ptr);
          free(*ptr);
          printf("freed!\n");
        }
        Ответить
        • То есть, в myfree передается void**?
          Ответить
          • В cleanup_function передаётся указатель на переменную с которой надо что-то сделать. Каст в void** тут для того, чтобы разыменовать и получить значение этой переменной.
            Ответить
            • free(*(void **)ptr)
              Мы же не передаем значение указателя в free, мы передаем указатель.
              Ответить
              • Смотри, x имеет тип char*, память под массив выделяется маллокой, он возвращает указатель на блок памяти, этот указатель мы записываем в x, в myfree передаётся не само значение x(не сам указатель), а указатель на него (указатель на указатель), т.е. чтобы получить значение x надо извлечь указатель по адресу, который передали в функцию.
                Ответить
            • Хрень какая-то получается. j123123, где в доках написано, что в myfree передаётся &x, а не x?
              Ответить
              • В описании к говнокоду же:
                The function must take one parameter, a pointer to a type compatible with the variable.
                Ответить
                • А, тьфу, точно же, тип переменной-то у нас — «char *».
                  Ответить
    • Сишненькое RAII завезли?
      Ответить
      • Лучше бы что-нибудь типа гошного "defer" завезли, более гибко было бы.
        Ответить
      • https://wandbox.org/permlink/fkHNkmWBrnZ06Wuq

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        
        // https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
        #define MK_ARR(type, name, freefunc, ...) \
        type * name __attribute__ (( cleanup (freefunc)  )) = \
        ({  \
          type *m____tmp = malloc( sizeof ( (type[]){__VA_ARGS__} ) ); \
          struct { typeof( (type[]){__VA_ARGS__}  ) arr;} tmpvar = {{__VA_ARGS__}}; \
          memcpy(m____tmp, tmpvar.arr,  sizeof((type[]){__VA_ARGS__}) ); \
          m____tmp; \
        })
        
        void myfree(void *ptr)
        {
          printf("%p\n", *(void **)ptr);
          free(*(void **)ptr);
          printf("freed!\n");
        }
        
        
        
        int main(void) {
          MK_ARR(int, x, myfree, 1, 2, 3);
          printf("%p {%d %d %d}\n", x, x[0], x[1], x[2]);
          return 0;
        }
        Ответить
        • Хотя еще можно впилить проверку, что если malloc вернул NULL

          Или даже сделать чтоб:
          #define MK_ARR(type, name, mallocfunc, freefunc, ...)
          Чтоб кастомный аллокатор
          Ответить
        • https://wandbox.org/permlink/btXuxt1Gk3NENoxy
          Улучшил
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          
          #define MK_ARR(type, name, mallocfunc, freefunc, ...) \
          type * name __attribute__ (( cleanup (freefunc)  )) = \
          ({  \
            typeof(type) *m____tmp = mallocfunc( sizeof ( (type[]){__VA_ARGS__} ) ); \
            if (m____tmp == NULL) \
            { \
              exit(EXIT_FAILURE); \
            } \
            typeof( (typeof(type)[]){__VA_ARGS__}  ) tmpvar = {__VA_ARGS__}; \
            memcpy(m____tmp, tmpvar,  sizeof((type[]){__VA_ARGS__}) ); \
            m____tmp; \
          })
          
          void myfree(void *ptr)
          {
            printf("freeing %p\n", *(void **)ptr);
            free(*(void **)ptr);
            printf("freed!\n");
          }
          
          int main(void) {
            MK_ARR(int, x, malloc, myfree, 1, 2, 3);
            printf("%p: {%d %d %d}\n", x, x[0], x[1], x[2]);
            return EXIT_FAILURE;
          }
          Ответить
      • Сишненькое RAII без GNU расширений я уже когда-то скидывал https://govnokod.ru/24517
        Ответить
    • void myfree(void **ptr) {
      	printf("%p\n", *ptr);
      	free(*ptr); printf("freed!\n");
      }
      Ответить
      • тогда компилятор ругнется на то, что у нас в функцию передается char **, но сама функция принимает void **
        Ответить
    • Ничего не понял, я просто выделяю память в стеке и теку.
      Ответить
    • Лень искать в стандарте это.
      Это туда входит?
      Ответить

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