Intereting Posts
NCURSES printw Получение правильного вывода кодов клавиш для RETURN и SPACE free (): недействительный следующий размер (нормальный) на fclose. Но не тогда, когда Valgrind запускает Ограничение входа в C Редактирование строки в текстовом файле с использованием временного файла C xv6 добавляет системный вызов, который учитывает системные вызовы crc32 () отсутствует при создании libzip на OSX 10.9 Разбор строки-формата printf формата? Правильный способ использования scanf / printf (и семейства) с фиксированными размерами? Почему компилятор не предупредил меня о пустом операторе if? Получение min, max и ave из пяти введенных чисел Реализация клиентского сервера Пропустить файл как аргумент командной строки Точность арифметики с плавающей запятой Почему это действительно C Перейти к загрузчику в STM32 с помощью приложения, то есть использовать Boot 0 и Boot 1 Pins в режиме загрузки из пользовательской вспышки

Будет ли сокращенный IF обеспечивать повышение эффективности по сравнению с IF по умолчанию?

Если у меня есть большой файл данных, содержащий целые числа произвольной длины, которые нужно отсортировать по второму полю:

1 3 4 5 1 4 5 7 -1 34 56 7 124 58394 1384 -1938 1948 3848089 -14850 0 1048 01840 1039 888 //consider this is a LARGE file, the data goes on for quite some time 

и я призываю qsort быть моим оружием выбора, внутри моей функции сортировки, будет использовать сокращенный IF, обеспечивающий значительное повышение производительности до общего времени, которое требуется для сортировки данных? Или это сокращенный IF используется только как инструмент удобства для организации кода?

 num2 = atoi(Str); num1 = atoi(Str2); LoggNum = (num2 > num1) ? num2 : num1; //faster? 

 num2 = atoi(Str); num1 = atoi(Str2); if(num2 > num1) //or the same? LoggNum = num2; else LoggNum = num1; 

    Любой современный компилятор будет создавать идентичный код в этих двух случаях, разница одна только в стиле и удобстве.

    На этот вопрос нет ответа … компилятор может генерировать любой код, который он считает подходящим. Тем не менее, только очень глупый компилятор создаст значительно другой код для этих случаев. Вы должны написать все, что вам лучше всего выразить, как работает ваша программа … мне тройная версия оператора более кратким и читабельна, но люди, не привыкшие к C и / или C ++, могут сначала определить версию if / else.

    Если вы заинтересованы в таких вещах и хотите лучше понять, как генерировать код, вы должны научиться вызывать ваш компилятор с просьбой подготовить выход на ассемблере, содержащий инструкции процессора для программы. Например, компиляторы GNU принимают флаг -S который создает файлы языка ассемблера .s .

    Единственный способ узнать – это профиль. Тем не менее, тернарный оператор позволяет выполнить инициализацию объекта:

     Sometype z = ( x < y) ? something : somethingElse; // copy initialization 

    С if-else вам нужно будет использовать дополнительное назначение, чтобы получить эквивалентное поведение.

     SomeType z; // default construction if ( x < y) { z = something; // assignment } else { z = somethingElse; // assignment } 

    Это может оказать влияние, если накладные расходы на присвоение SomeType велики.

    Мы протестировали эти два утверждения в VC 2010:

    Генетическая assembly для? =:

      01207AE1 cmp byte ptr [ebp-101h],0 01207AE8 jne CTestSOFDlg::OnBnClickedButton1+47h (1207AF7h) 01207AEA push offset (1207BE5h) 01207AEF call @ILT+840(__RTC_UninitUse) (120134Dh) 01207AF4 add esp,4 01207AF7 cmp byte ptr [ebp-0F5h],0 01207AFE jne CTestSOFDlg::OnBnClickedButton1+5Dh (1207B0Dh) 01207B00 push offset (1207BE0h) 01207B05 call @ILT+840(__RTC_UninitUse) (120134Dh) 01207B0A add esp,4 01207B0D mov eax,dword ptr [num2] 01207B10 cmp eax,dword ptr [num1] 01207B13 jle CTestSOFDlg::OnBnClickedButton1+86h (1207B36h) 01207B15 cmp byte ptr [ebp-101h],0 01207B1C jne CTestSOFDlg::OnBnClickedButton1+7Bh (1207B2Bh) 01207B1E push offset (1207BE5h) 01207B23 call @ILT+840(__RTC_UninitUse) (120134Dh) 01207B28 add esp,4 01207B2B mov ecx,dword ptr [num2] 01207B2E mov dword ptr [ebp-10Ch],ecx 01207B34 jmp CTestSOFDlg::OnBnClickedButton1+0A5h (1207B55h) 01207B36 cmp byte ptr [ebp-0F5h],0 01207B3D jne CTestSOFDlg::OnBnClickedButton1+9Ch (1207B4Ch) 01207B3F push offset (1207BE0h) 01207B44 call @ILT+840(__RTC_UninitUse) (120134Dh) 01207B49 add esp,4 01207B4C mov edx,dword ptr [num1] 01207B4F mov dword ptr [ebp-10Ch],edx 01207B55 mov eax,dword ptr [ebp-10Ch] 01207B5B mov dword ptr [LoggNum],eax 

    и для if else оператор:

      01207B5E cmp byte ptr [ebp-101h],0 01207B65 jne CTestSOFDlg::OnBnClickedButton1+0C4h (1207B74h) 01207B67 push offset (1207BE5h) 01207B6C call @ILT+840(__RTC_UninitUse) (120134Dh) 01207B71 add esp,4 01207B74 cmp byte ptr [ebp-0F5h],0 01207B7B jne CTestSOFDlg::OnBnClickedButton1+0DAh (1207B8Ah) 01207B7D push offset (1207BE0h) 01207B82 call @ILT+840(__RTC_UninitUse) (120134Dh) 01207B87 add esp,4 01207B8A mov eax,dword ptr [num2] 01207B8D cmp eax,dword ptr [num1] 01207B90 jle CTestSOFDlg::OnBnClickedButton1+100h (1207BB0h) 01207B92 cmp byte ptr [ebp-101h],0 01207B99 jne CTestSOFDlg::OnBnClickedButton1+0F8h (1207BA8h) 01207B9B push offset (1207BE5h) 01207BA0 call @ILT+840(__RTC_UninitUse) (120134Dh) 01207BA5 add esp,4 01207BA8 mov eax,dword ptr [num2] 01207BAB mov dword ptr [LoggNum],eax 01207BB0 cmp byte ptr [ebp-0F5h],0 01207BB7 jne CTestSOFDlg::OnBnClickedButton1+116h (1207BC6h) 01207BB9 push offset (1207BE0h) 01207BBE call @ILT+840(__RTC_UninitUse) (120134Dh) 01207BC3 add esp,4 01207BC6 mov eax,dword ptr [num1] 01207BC9 mov dword ptr [LoggNum],eax 

    как вы можете видеть? = оператор имеет еще две команды asm:

     01207B4C mov edx,dword ptr [num1] 01207B4F mov dword ptr [ebp-10Ch],edx 

    который требует больше тиков процессора.

    для цикла с размером 97000000, если другое быстрее.

    Эта конкретная оптимизация укусила меня в реальной базе кода, где переход от одной формы к другой в функции блокировки обеспечил 10% времени выполнения в контрольном контроле.

    Давайте проверим это с помощью gcc 4.2.1 на MacOS:

     int global; void foo(int x, int y) { if (x < y) global = x; else global = y; } void bar(int x, int y) { global = (x < y) ? x : y; } 

    Мы получаем (убираем):

     _foo: cmpl %esi, %edi jge L2 movq _global@GOTPCREL(%rip), %rax movl %edi, (%rax) ret L2: movq _global@GOTPCREL(%rip), %rax movl %esi, (%rax) ret _bar: cmpl %edi, %esi cmovle %esi, %edi movq _global@GOTPCREL(%rip), %rax movl %edi, (%rax) ret 

    Учитывая, что инструкции cmov были добавлены специально для повышения производительности такого рода операций (избегая конвейерных киосков), ясно, что «?:» В этом конкретном компиляторе работает быстрее.

    Должен ли компилятор генерировать один и тот же код в обоих случаях? Да. Будет ли он? Нет, конечно, нет, компилятор не идеален. Если вы действительно заботитесь о производительности (в большинстве случаев вам не следует), проверьте и посмотрите.