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

    +140

    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
    44. 44
    45. 45
    46. 46
    HIMAGELIST ImageList_LoadImageV(PVOID ImageBase, PCWSTR a[], int level)
    {
    	PIMAGE_RESOURCE_DATA_ENTRY pirde;
    	PBITMAPINFOHEADER pbih;
    	DWORD cx, cy, cb, n, ofs;
    	if (
    		0 <= LdrFindResource_U(ImageBase, a, level, &pirde) && 
    		0 <= LdrAccessResource(ImageBase, pirde, (void**)&pbih, &cb) &&
    		cb > sizeof(BITMAPINFOHEADER) &&
    		pbih->biSize >= sizeof(BITMAPINFOHEADER) &&
    		(cx = pbih->biWidth) <= (cy = pbih->biHeight) &&
    		!(cy % cx) &&
    		pbih->biBitCount == 32 &&
    		(ofs = pbih->biSize) + (cx * cy << 2) == cb
    		)
    	{
    		n = cy / cx, cb = cx * cx << 2;
    
    		if (HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32, n, 0))
    		{
    			BITMAPINFO bi = { {sizeof(BITMAPINFOHEADER), cx, cx, 1, 32 } };
    
    			if (HDC hdc = GetDC(0))
    			{
    				if (HBITMAP hbmp = CreateCompatibleBitmap(hdc, cx, cx))
    				{
    					do ; while (
    						SetDIBits(hdc, hbmp, 0, cx, RtlOffsetToPointer(pbih, ofs), &bi, DIB_RGB_COLORS) &&
    						0 <= ImageList_Add(himl, hbmp, 0) &&
    						(ofs += cb, --n)
    						);
    
    					DeleteObject(hbmp);
    				}
    
    				ReleaseDC(0, hdc);
    			}
    
    			if (!n) return himl;
    
    			ImageList_Destroy(himl);
    		}
    	}
    
    	return 0;
    }

    Запостил: zhukas, 14 Декабря 2014

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

    • А разве в Си можно переменные внутри if объявлять?
      А вообще, хакер, вылитый хакер. Особенно do ; while - я даже не знал, что так можно.
      Ответить
      • > А разве в Си можно переменные внутри if объявлять
        Нельзя, емнип. Так что это кресты.
        Ответить
        • в С99 можно.
          Ответить
          • Пруф?
            Ответить
            • Пункт 6.8.5.3 (черновика) стандарта С99.
              for ( clause-1 ; expression-2 ; expression-3 ) statement
              ...
              If clause-1 is a
              declaration, the scope of any identifiers it declares is the remainder of the declaration and
              the entire loop, including the other two expressions; it is reached in the order of execution
              before the first evaluation of the controlling expression.
              Ответить
      • > А разве в Си можно переменные внутри if объявлять?

        Можно в начале любого блока, даже в C89.
        Ответить
      • > do ; while (...);
        Кстати, а это же ничем не отличается от while (...);
        Ответить
        • Зато так спокойнее, потому что случайно забытый do выше по коду не помешает. Или нет?
          Ответить
          • Ну вот. Всегда говорилось что while не нужен, всё то и даже больше умеет for(;;).

            Зачем писать уродливые костыли, боясь мифических do, если можно юзать for, как единый цикл с предусловием и не париться?
            Ответить
        • в принципе да - по семантике. и по конечному коду - если компилировать с оптимизацией. но без оптимизации код как не странно будет разный. циклы do {...} while (...); короче while(...) {...} на 1 jmp инструкцию в цикле. например:
          while (func());

          @@1: call func
          text rax,rax
          jz @@2
          jmp @@1
          @@2:
          --------------------------
          do ; while (func());
          @@1: call func
          text rax,rax
          jnz @@1
          Ответить
          • Еще вот так некоторые компилеры делают:
            ; while (func()) { ... body ... }
                jmp check
            loop:
                ... body ...
            check:
                call func
                test rax, rax
                jne loop
            Ответить
            • на самом деле это и есть оптимизация цикла while( func() ) { body; } . (cl.exe так всегда делает) . копилятор (CL) сводит его к циклу
              goto check;
              do
              {
              body;

              check:
              }
              while( func() );
              в данном случае тоже есть 1 дополнительная инструкция - jmp check - НО она выполняется только 1 раз, а не в цикле
              Ответить
          • P.S. gcc даже на -O0 одинаково собрало этот пустой цикл (по второму варианту, только с промежуточной буловской переменной):
            .L4:
                    call    _Z4funcv
                    testl   %eax, %eax
                    setne   %al
                    testb   %al, %al
                    jne     .L4
            Ответить
            • Ой, это было g++... Вот gcc:
              .L4:
                      movl    $0, %eax
                      call    func
                      testl   %eax, %eax
                      jne     .L4
              Зачем там зануление eax - я х.з.
              Ответить
            • Хмм, а интересно - для while (func()); перед циклом втыкается nop, а для while ; do (func()) - нет. Неисповедимы пути компилятора, которому запретили оптимизировать. Видимо, этот nop превратился бы в jmp, если бы тело было непустым.
              Ответить
              • nop честно говоря никогда не видел. всё что я пишу относиться к CL только. в принципе логика есть. когда оптимизация запрещена - cl просто всё переводит в asm как написано. при этом do while циклы чуть-чуть эффективнее чем просто while. (на 1 jmp в цикле). при оптимизации CL стремиться вынести jmp из цикла (что бы она выполнялось только 1 раз) - при этом фактически while() трансформируется в goto;do..while() . но совсем избавиться от jmp можно только в случае пустого body.
                Ответить
      • >Особенно do ; while - я даже не знал, что так можно.
        Ну for же можно. И if. И обычный while.
        Я за принудительные операторные скобки и возможно отказ от коварного оператора запятая.
        Хотя крестоблядь везде болото найдёт, чтобы в нём застрелиться в ногу.
        Ответить
        • А switch с одним выражением? Или тело функции, если в нем всего одно выражение? Разные Си-подобные к этому по-разному относятся. Или try-catch там где он есть.
          Я не против того, чтобы не писать скобки там где не нужно. Что мне кажется не хорошо - скобки выполняют две функции (в Си) - лексические блоки, и просто грамматическую функцию объединения нескольких выражений в одно. И иногда используя их ради одной из функций зачем-то получаешь вторую.
          Ответить
          • >А switch с одним выражением?
            Ну есть case без выражений, для того чтобы перечислить несколько значений.
            switch(1) {
            case 1:case 2:;
            }
            Да в том-то и дело что тут полная неконсистентность.

            >Или тело функции, если в нем всего одно выражение?
            >разные Си-подобные к этому по-разному относятся.
            Хотя лямбды в C# (x => x+1;), Java (x -> x+1; ) и драфте ECMA6 допускают сахарную запись без фигурных скобок, если там один оператор. Не знаю насчёт крестов, может и там сделали.
            Ответить
    • > pirde
      Raissya v pirde.
      Ответить
    • Ааааа опять Йода, суки.
      Ответить

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