Что лучше использовать: cout / wcout или printf? [закрыт]

224
08 сентября 2018, 12:20

Собственно, вопрос в заголовке. Пожалуйста, дайте подробный ответ.

Answer 1

Как завещал нам Страуструп, лучше потоки чем printf. Ибо потоки, как минимум, типобезопасны.

Например есть код:

int i;
cout<<i;
printf("%i",i);

Представим, что в процессе работы пришлось сменить тип переменной (это встречается сплошь и рядом):

float i;
cout<<i;
printf("%f",i);

Как видно, при использовании потока ничего не поменялось. А при использовании printf пришлось править форматную строку. Если printf много в коде, то везде править форматную строку во всех printf очень утомительно и черевато ошибками.

UPD1:

Предположить легко. Однако, на самом деле это последствие идеи предоставления пользователям языка средств для его расширения -- т.е. конструирования собственных типов данных и операций над ними, что влечет перегрузку операций (т.е. одно и то же обозначение операций в зависимости от типов операндов дает разный результат). Хорошо это или плохо для реальной практики программирования, учитывающей качество персонала, вопрос дискуссионный

Уж не знаю насколько потоки следствие идеи перегрузки операций. Может быть это и так. В любом случае, в варианте с printf тип операнда указывается два раза. Один раз в форматной строке, а второй раз собственно имя переменной говорит компилятору какой это тип. А два раза повторять одну и ту же информацию не есть хорошо. Потому что править приходится в двух местах, а не в одном месте. Так что идея с потоками (независимо от источника ее появления, будь то перегрузка операций или просто желание избавится от форматной строки) еще позволила избавится от ненужного дублирования информации.

Кстати, перегрузить операции можно было бы и с printf. Или в потоках оставить форматную строку. Ну если все делать через одно место конечно.

Что касается квалификации персонала, то квалификация постоянно растет. Старая школа может долбать любимый printf до посинения, пока самим не надоест вылавливать ошибки форматов. Новое поколение не знает таких ужасов и весело применяет потоки.

UPD2:

Кстати, вывод через потоки в общем случае быстрее, чем вывод через printf. Объясняется это тем, что при выводе через потоки разбор типов происходит на этапе компиляции и в рантайме разбора типов нет, а там есть только вывод значения. В случае же с printf происходит разбор форматной строки в рантайме, то есть компилированный код передает управление интерпретатору форматной строки. А, как известно, интерпретатор работает в 100-1000 раз медленнее, чем компилированный код.

Ранние трансляторы С++ создавали потоковый вывод как надстройку над выводом printf и разницы в скорости не было (но все равно была разница в типобезопасности, так как форматные строки формировались автоматически). Современные трансляторы С++ делают потоковый вывод как надо, без использования printf. И это (теоретически) повышает быстродействие вывода.

Так что скорость вывода это еще один аргумент, который заставляет программистов выбирать потоки вместо старого подхода с printf.

UPD3:

Но и объем скомпилированного кода больше.

Объем скомпилированного кода при выводе в поток не больше, чем при использовании printf.

Пример:

int var1=1;
int var2=2;
cout<<var1;
cout<<var2;

В этом примере строки вывода

cout<<var1;
cout<<var2;

разворачиваются в обычные вызовы подпрограмм вывода, а вовсе не в последовательные повторения кода.

скорость встроенных при компиляции (как следствие реализации templates) преобразований выше.

Скорость вывода при использовании printf меньше именно из-за того, что разбор форматной строки происходит в рантайме. В случае использования потоков нет разбора форматной строки в рантайме и также нет оверхеда из-за шаблонов потому что там вставляется не шаблон, а обычный вызов подпрограммы вывода для соответствующего типа. Это легко проверить, если посмотреть ассемблерный код простого примера, приведенного выше. Транслятор Visual Studio 2017.

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.14.26433.0 
    TITLE   C:\user\basil\rttsched\etudes\etude2\etude2\etude2\etude2.cpp
    .686P
    .XMM
    include listing.inc
    .model  flat
INCLUDELIB MSVCRTD
PUBLIC  ?__empty_global_delete@@YAXPAX@Z        ; __empty_global_delete
PUBLIC  ?__empty_global_delete@@YAXPAXI@Z       ; __empty_global_delete
PUBLIC  _main
EXTRN   __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z:PROC
EXTRN   __RTC_CheckEsp:PROC
EXTRN   __RTC_InitBase:PROC
EXTRN   __RTC_Shutdown:PROC
EXTRN   __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A:BYTE
;   COMDAT rtc$TMZ
rtc$TMZ SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ ENDS
;   COMDAT rtc$IMZ
rtc$IMZ SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
rtc$IMZ ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; File c:\user\basil\rttsched\etudes\etude2\etude2\etude2\etude2.cpp
;   COMDAT _main
_TEXT   SEGMENT
_var2$ = -20                        ; size = 4
_var1$ = -8                     ; size = 4
_main   PROC                        ; COMDAT
    push    ebp
    mov ebp, esp
    sub esp, 216                ; 000000d8H
    push    ebx
    push    esi
    push    edi
    lea edi, DWORD PTR [ebp-216]
    mov ecx, 54                 ; 00000036H
    mov eax, -858993460             ; ccccccccH
    rep stosd
    mov DWORD PTR _var1$[ebp], 1
    mov DWORD PTR _var2$[ebp], 2
    mov esi, esp
    mov eax, DWORD PTR _var1$[ebp]
    push    eax
    mov ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
    call    DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
    cmp esi, esp
    call    __RTC_CheckEsp
    mov esi, esp
    mov eax, DWORD PTR _var2$[ebp]
    push    eax
    mov ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
    call    DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
    cmp esi, esp
    call    __RTC_CheckEsp
    xor eax, eax
    pop edi
    pop esi
    pop ebx
    add esp, 216                ; 000000d8H
    cmp ebp, esp
    call    __RTC_CheckEsp
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; File c:\user\basil\rttsched\etudes\etude2\etude2\etude2\etude2.cpp
;   COMDAT ?__empty_global_delete@@YAXPAXI@Z
_TEXT   SEGMENT
___formal$ = 8                      ; size = 4
___formal$ = 12                     ; size = 4
?__empty_global_delete@@YAXPAXI@Z PROC          ; __empty_global_delete, COMDAT
    push    ebp
    mov ebp, esp
    sub esp, 192                ; 000000c0H
    push    ebx
    push    esi
    push    edi
    lea edi, DWORD PTR [ebp-192]
    mov ecx, 48                 ; 00000030H
    mov eax, -858993460             ; ccccccccH
    rep stosd
    pop edi
    pop esi
    pop ebx
    mov esp, ebp
    pop ebp
    ret 0
?__empty_global_delete@@YAXPAXI@Z ENDP          ; __empty_global_delete
_TEXT   ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; File c:\user\basil\rttsched\etudes\etude2\etude2\etude2\etude2.cpp
;   COMDAT ?__empty_global_delete@@YAXPAX@Z
_TEXT   SEGMENT
___formal$ = 8                      ; size = 4
?__empty_global_delete@@YAXPAX@Z PROC           ; __empty_global_delete, COMDAT
    push    ebp
    mov ebp, esp
    sub esp, 192                ; 000000c0H
    push    ebx
    push    esi
    push    edi
    lea edi, DWORD PTR [ebp-192]
    mov ecx, 48                 ; 00000030H
    mov eax, -858993460             ; ccccccccH
    rep stosd
    pop edi
    pop esi
    pop ebx
    mov esp, ebp
    pop ebp
    ret 0
?__empty_global_delete@@YAXPAX@Z ENDP           ; __empty_global_delete
_TEXT   ENDS
END

Видно, что вызов

cout<<var1;

разворачивается в обычный вызов подпрограммы

call    
DWORD PTR __imp_??6?$basic_ostream@DU$char_traits@D@std@@@std@@QAEAAV01@H@Z

и никаких шаблонов тут нет.

UPD4:

мы пишем программы не для компьютера, а для других программистов

Довольно спорное утверждение. Проще переписать весь код, чем править чужое. Ибо невозможно до конца понять, какие мысли (часто неверные) были у человека, когда он писал код.

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

Нет, надо не только использовать то, чем владеешь, но и осваивать новые, более продвинутые инструменты вроде потоков, которые для нас придумывают разные головастые страуструпы. Если бы мы не осваивали новые инструменты, то мы бы до сих пор программировали в машинных кодах.

READ ALSO
Сортировка массивов и запись в файл

Сортировка массивов и запись в файл

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

235
3d график в Qt5?

3d график в Qt5?

Как строить графики с помощью Qt5? Qwt3D не обновлялся с 2007 года и вроде для Qt4Находил решение от частных лиц

176
Как привязать QGridLayout к размеру окна?

Как привязать QGridLayout к размеру окна?

Цель: при изменении размера окна, изменялся размер QGridLayout

190
Blur в LinearLayout Background

Blur в LinearLayout Background

В интернете множество библиотек связанных с Blur эффектами, но почему-то я не нашел библиотек и даже способов сделать Blur в LinearLayout Background

183