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

    −6

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    #include <stdio.h>
    
    #define my_type unsigned short
    
    int main(void) 
    {
        my_type a = 0;
    
        printf("%d\n", a);
    
        return 0;
    }

    Экое извращение

    Запостил: Ksyrx, 28 Августа 2019

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

    • показать все, что скрытоvanished
      Ответить
    • Учись, малец:
      http://govnokod.ru/user/25930/codes
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • Ну и в чем прикол? В автокасте?
      Ответить
      • показать все, что скрытоvanished
        Ответить
      • Прикола нет, и автокаста никакого нет. Если ты о 9-й строчке, то там ushort всегда при передаче в любую функцию займёт минимум одну ячейку в стеке или один регистр, что равно размеру инта, ну или лонга. (кстати, почему на 64-битах инт остался 32-битным?)

        Именно поэтому я за "Си".
        Ответить
        • показать все, что скрытоvanished
          Ответить
          • >> С спецификации сшечки нет ячеек стека

            Именно поэтому я за «Си».

            Кстати, именно поэтому на других процессорах можно обломаться, если выдвигать смелые предположения.
            Ответить
            • показать все, что скрытоvanished
              Ответить
              • В "сишечке нет стека" - это просто скорыто почти всегда от программиста (кстати не понятно зачем, лоу-левел же). Но в реале он всегда есть, стек - самая подходящая структуры для хранения параметров, адресов возвратов и локальный переменных.

                А чот такое автоматическая переменная я не совсем понял, ты про сишный auto? Назуй он вообще нужен и как это отменяте существовование стека*+?
                Ответить
        • На x86 минимальный размер данных, который можно запушить в стек, равен 16 битам (двум байтам), причём даже в 64-битном режиме.

          Сколько пушит сишка, зависит от коллконвеншона.
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • Да, именно так. В x64 дофига префиксов размера, так что многие инструкции можно сделать 32-битными или 16-битными. Вот инструкции для 8-битных данных идут отдельно.
              Ответить
          • А как я тогда узнаю, сколько байт из стека доставать? или va_arg должен эту ситуацию разрулить? Просто мне вспоминается, что с va_arg(va, char) какие-то проблемы возникают, что он один байт вместо двух вытаскивает...
            Ответить
            • Какой багор )))

              Прочитал я про вариадические функции в сишке. Какое же говно...

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

              Т. е. при вызове макроса va_arg нельзя указывать типы char, short, float, int8_t и тому подобные. Можно указывать только типы, которые по размеру не меньше, чем int и double, а также указатели.

              Какой размер имеет этот самый int, зависит от конкретного компилятора. Можно попасть в ситуацию, когда для какой-нибудь платформы есть несколько компиляторов и слинковать вместе сгенерированный ими код не получится.
              Ответить
              • показать все, что скрытоvanished
                Ответить
                • Надо копать.

                  Точно нельзя на x86 передавать структуру размером один байт, потому что вызывающий код запушит как минимум два байта, а тупой макрос va_arg прибавит к указателю единицу. Чтобы принять такую структуру, придётся дополнительно объявлять фиктивный тип размером в два байта.

                  Да вообще для всех структур нечётного размера придётся вводить фиктивный тип, округлённый до ближайшего чётного.
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • Проверял, по умолчанию sizeof(struct{int8_t field;}) == 1. Дебильный макрос va_arg увеличит адрес на единицу и в качестве следующего параметра прочитает мусор.

                      Если размер структуры нечётный, нужно явно объявить вспомогательный тип данных. Вручную мусорное поле можно и не добавлять, а прописать прагму для выравнивания (хотя нужно проверить).
                      Ответить
                      • Хотя в «MINGW» вот что нашёл:
                        #if defined(_M_IX86)
                        
                        #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
                        #define _crt_va_start(v,l)	((v) = (va_list)_ADDRESSOF(l) + _INTSIZEOF(l))
                        #define _crt_va_arg(v,l)	(*(l *)(((v) += _INTSIZEOF(l)) - _INTSIZEOF(l)))
                        #define _crt_va_end(v)		((v) = (va_list)0)
                        #define _crt_va_copy(d,s)	((d) = (s))
                        
                        #elif defined(_M_AMD64)
                        
                        #define _PTRSIZEOF(n) ((sizeof(n) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
                        #define _ISSTRUCT(t)  ((sizeof(t) > sizeof(void*)) || (sizeof(t) & (sizeof(t) - 1)) != 0)
                        #define _crt_va_start(v,l)	((v) = (va_list)_ADDRESSOF(l) + _PTRSIZEOF(l))
                        #define _crt_va_arg(v,t)	_ISSTRUCT(t) ?						\
                        				 (**(t**)(((v) += sizeof(void*)) - sizeof(void*))) :	\
                        				 ( *(t *)(((v) += sizeof(void*)) - sizeof(void*)))
                        #define _crt_va_end(v)		((v) = (va_list)0)
                        #define _crt_va_copy(d,s)	((d) = (s))
                        
                        #elif defined(_M_IA64)
                        
                        #error VARARGS not implemented for IA64
                        
                        #else
                        
                        #error VARARGS not implemented for this TARGET
                        
                        #endif /* cpu ifdefs */


                        Для X86 он округлит sizeof до размера, кратного инту; для AMD64 он округлит до размера, кратного void*; на остальных платформах пошлёт напитон.
                        Ответить
                • Чем старше стандарт - тем хуже язык. Закопайте уже его и переходите на делфи.
                  Ответить
                  • Кстати, в Delphi есть array of const — это массив не сырых данных, а данных с метаданными, а также open arrays и динамические массивы, когда при вызове функций рядом с данными пушится их размер. В сишке то же самое придётся делать вручную (поэтому у функций с вариативными параметрами обычно явно первым параметром передают размер или строку формата, как у printf).
                    Ответить
                  • показать все, что скрытоvanished
                    Ответить
                • Проверил на x86-32 (gcc на x86-64 игнорирует cdecl и хочет ms_abi или sysv_abi):
                  #include <stdio.h>
                  #include <stdint.h>
                  typedef struct __attribute__ ((__packed__)) {uint8_t field;} TPituh;
                  
                  void __attribute__ ((cdecl)) Dump(TPituh pituh1, TPituh pituh2) {
                      printf("pituh1       = %08x\n", pituh1); // ffffff55
                      printf("pituh2       = %08x\n", pituh2); // ffffffaa
                      printf("pituh1.field = %08x\n", pituh1.field); // 00000055
                      printf("pituh2.field = %08x\n", pituh2.field); // 000000aa
                      printf("raw data 1   = %08x\n", *(uint32_t *)&pituh1); // 00404155
                      printf("raw data 2   = %08x\n", *(uint32_t *)&pituh2); // 000000aa
                      printf("__builtin_frame_address(0)+8    = %08x\n", *(uint32_t *)(__builtin_frame_address(0)+8)); // 00404155
                      printf("__builtin_frame_address(0)+12   = %08x\n", *(uint32_t *)(__builtin_frame_address(0)+12)); // 000000aa
                      printf("__builtin_frame_address(1)-10   = %08x\n", *(uint32_t *)(__builtin_frame_address(1)-10)); // 000655aa -- это код из main, в main они лежат плотно
                  }
                  
                  int main(){
                      TPituh pituh1 = {.field=0x55};
                      TPituh pituh2 = {.field=0xAA};
                      printf("sizeof(pituh1) = %d\n", sizeof(pituh1)); // sizeof(pituh1) = 1
                      Dump(pituh1, pituh2);
                      return 0;
                  }


                  В общем, gcc на x86-32 структуры хранит плотно, но когда пушит, дополняет случайным мусором до четырёх байтов.
                  Ответить
      • показать все, что скрытоvanished
        Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить

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