C ++에서 'printf'와 'cout'
C ++ printf()와 coutC ++ 의 차이점은 무엇입니까 ?
이 질문의 모든 사람들이 질문이 단지 차이점을 요구하더라도. std::cout보다 더 낫다고 주장하는 것에 놀랐습니다 printf. 이제 차이점 std::cout은 C ++ printf이며 C입니다 (그러나 C의 거의 다른 것과 마찬가지로 C ++에서 사용할 수 있습니다 ). 이제 저는 정직합니다. 모두 printf와 std::cout그들의 장점이있다.
실제 차이점
확장 성
std::cout확장 가능합니다. 사람들 printf은 확장 할 수 있다고 말하지만 그러한 확장은 C 표준에 언급되어 있지 않으므로 비표준 기능을 사용해야하지만 일반적인 비표준 기능은 존재하지 않습니다. (이미 존재하는 형식과 충돌하기 쉽습니다).
달리 printf, std::cout연산자 오버로딩에 완전히 의존하므로 사용자 정의 형식과 아무 문제 없다 - 당신이 할 모든 서브 루틴 복용 정의입니다 std::ostream첫 번째 인수로하고 두 번째와 같은 유형입니다. 따라서 네임 스페이스 문제는 없습니다. 클래스가 한 문자로 제한되지 않는 한 std::ostream오버로드 작업을 수행 할 수 있습니다 .
그러나 많은 사람들이 확장하기를 원한다고 의심합니다 ostream(솔직히 말하면 쉽게 확장 할 수는 없지만 그러한 확장을 거의 보지 못했습니다). 그러나 필요한 경우 여기에 있습니다.
통사론
그것은 쉽게 발견 할 수 있기 때문에, 모두 printf와는 std::cout다른 구문을 사용합니다. printf패턴 문자열 및 가변 길이 인수 목록을 사용하여 표준 함수 구문을 사용합니다. 사실, printfC가 가지고있는 이유입니다- printf형식이 너무 복잡하여 사용할 수 없습니다. 그러나 std::cout다른 API ( operator <<자체를 반환 하는 API)를 사용합니다.
일반적으로 C 버전이 더 짧아 지지만 대부분의 경우 중요하지 않습니다. 많은 인수를 인쇄하면 차이점이 눈에 is니다. Error 2: File not found.오류 번호를 가정 하고와 같은 것을 작성해야 하고 설명이 자리 표시 자 인 경우 코드는 다음과 같습니다. 두 예제 모두 동일하게 작동합니다 ( 완전히 일종의 std::endl버퍼를 비 웁니다).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
이것이 너무 미친 것처럼 보이지는 않지만 (두 배 길어집니다) 실제로 인쇄하는 대신 인수의 형식을 지정할 때 상황이 더 미쳐집니다. 예를 들어, 같은 것을 인쇄하는 것은 0x0424미친 짓입니다. 이것은 std::cout혼합 상태와 실제 값으로 인해 발생 합니다. 나는 std::setfillC ++ 이외의 유형 과 같은 언어를 보지 못했습니다 . printf인수와 실제 유형을 명확하게 구분합니다. 나는 잡음이 너무 많기 때문에 버전 printf과 비교하여 iostream버전 을 유지하는 것을 선호합니다 .
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
번역
이것이 printf거짓말 의 진정한 이점입니다 . printf형식 문자열은 ... 음 문자열입니다. 그것은의 operator <<남용에 비해 번역하기가 정말 쉽습니다 iostream. 가정하면 gettext()함수가 변환하고 표시 할 Error 2: File not found.같을 것이다 이전에 표시된 형식 문자열의 번역을 얻기 위해 코드를 :
printf(gettext("Error %d: %s.\n"), id, errors[id]);
자, 우리가 Fictionish로 번역했다고 가정 해 봅시다. 오류 번호는 설명 뒤에 있습니다. 번역 된 문자열은 다음과 같습니다 %2$s oru %1$d.\n. 이제 C ++에서 어떻게해야합니까? 글쎄요 나는 당신이 가짜 할 수 추측 iostream구축 printf당신이 통과 할 수있는 gettext번역의 목적을 위해, 또는 무언가를. 물론 $C 표준은 아니지만 일반적으로 제 의견으로는 안전합니다.
특정 정수 유형 구문을 기억 / 조회 할 필요가 없습니다.
C에는 많은 정수 유형이 있으며 C ++도 마찬가지입니다. std::cout당신을 위해 핸들 모든 유형 동안 printf정수 유형에 따라 특정 구문을 필요는 (정수가 아닌 종류가 있습니다,하지만 당신이 실제로 사용할 수있는 유일한 정수가 아닌 유형 printf입니다 const char *(C 문자열을 사용하여 얻을 수있는 to_c방법을 std::string)). 예를 들어, 인쇄 size_t하려면을 사용해야 %zd하지만 int64_t을 사용해야합니다 %"PRId64". 표는 http://en.cppreference.com/w/cpp/io/c/fprintf 및 http://en.cppreference.com/w/cpp/types/integer 에서 사용 가능 합니다.
NUL 바이트를 인쇄 할 수 없습니다. \0
때문에 printfC ++ 문자열이 아닌 용도의 C 문자열이 특정 트릭없이 NUL 바이트를 인쇄 할 수 없습니다. 어떤 경우에는 그것을 사용하는 것이 가능 %c하여 '\0'그 분명히 해킹 있지만 인수로.
아무도 신경 쓰지 않는 차이점
공연
업데이트 : iostream속도가 너무 느려 일반적으로 하드 드라이브보다 느립니다 (프로그램을 파일로 리디렉션하는 경우). stdio많은 양의 데이터를 출력해야하는 경우 동기화를 비활성화 하면 도움 이 될 수 있습니다. STDOUT에 여러 줄을 쓰는 것과는 대조적으로 성능이 실제로 문제가되는 경우을 사용하십시오 printf.
누구나 성능에 관심이 있다고 생각하지만 아무도 그것을 측정 할 필요가 없습니다. 내 대답은 당신이 사용하는 경우 I / O는, 어쨌든 병목 현상없이하다는 것이다 printf나 iostream. 어셈블리를 빠르게 살펴보면 컴파일러 옵션 이 더 빠를 printf 수 있다고 생각합니다 ( -O3컴파일러 옵션을 사용하여 clang으로 컴파일 ). 내 오류 예제를 가정하면 printf예제는 cout예제 보다 적은 호출을 수행합니다 . 이다 int main와 함께 printf:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
두 개의 문자열과 2(숫자)가 printf인수 로 푸시되는 것을 쉽게 알 수 있습니다 . 그게 다야. 다른 것은 없습니다. 비교 iostream를 위해 어셈블리 로 컴파일됩니다. 아니요, 인라이닝이 없습니다. 모든 단일 operator <<호출은 다른 인수 세트를 갖는 다른 호출을 의미합니다.
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
그러나 솔직히 말하면 이것은 I / O가 병목 현상이기 때문에 아무 의미가 없습니다. 나는 iostream그것이 "유형 안전"이기 때문에 더 빠르지 않다는 것을 보여주고 싶었습니다 . 대부분의 C 구현은 printf계산 된 goto를 사용하여 형식을 구현 하므로 printf컴파일러가 인식하지 않아도 가능한 한 빠릅니다 printf(일부 컴파일러는 printf특정 경우에 최적화 할 수 없습니다 -일정한 문자열로 끝나는 문자열 \n은 일반적으로에 최적화됩니다 puts) .
계승
왜 상속을 원하는지 모르겠지만 ostream신경 쓰지 않습니다. 그것도 가능합니다 FILE.
class MyFile : public FILE {}
타입 안전
사실 가변 길이 인수 목록은 안전하지 않지만 printf경고를 활성화하면 널리 사용되는 C 컴파일러가 형식 문자열의 문제를 감지 할 수 있으므로 중요하지 않습니다 . 실제로 Clang은 경고를 활성화하지 않고이를 수행 할 수 있습니다.
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
로부터 C ++ FAQ :
[15.1] 왜
<iostream>전통적인 방식 대신에 사용해야<cstdio>합니까?형식 안전성을 높이고 오류를 줄이며 확장 성을 허용하며 상속성을 제공합니다.
printf()scanf()아마도 오류가 발생 하지 않았 음에도 불구하고 아마도 깨지지 않을 것입니다. 그러나 C ++ I / O가 할 수있는 것에 대해서는 둘 다 제한되어 있습니다. C ++ I / O (<<및 사용>>)는 C (printf()및 사용scanf())에 상대적입니다 .
- 보다 안전한 유형 :를 사용하면
<iostream>I / O되는 객체 유형을 컴파일러에서 정적으로 알 수 있습니다. 반대로<cstdio>"%"필드를 사용하여 유형을 동적으로 파악하십시오.- 오류 발생 가능성 감소 :를 사용하면
<iostream>I / O중인 실제 개체와 일치해야하는 중복 "%"토큰이 없습니다. 중복성을 제거하면 일련의 오류가 제거됩니다.- 확장 성 : C ++
<iostream>메커니즘을 사용하면 기존 코드를 손상시키지 않고 새로운 사용자 정의 유형을 I / O 할 수 있습니다. 모든 사람이 동시에 새로운 호환되지 않는 "%"필드를 추가 할 경우 혼란을 상상해printf()와scanf()?!- 상속 가능 : C ++
<iostream>메커니즘은std::ostreamand와 같은 실제 클래스에서 빌드됩니다std::istream. 달리<cstdio>의 'FILE*이 실제 수업 따라서 상속합니다. 즉, 스트림처럼 보이고 작동하는 다른 사용자 정의 항목을 가질 수 있지만 원하는 이상하고 멋진 작업을 수행 할 수 있습니다. 모르는 사용자가 작성한 수백만 줄의 I / O 코드를 자동으로 사용할 수 있으며 "확장 스트림"클래스에 대해 알 필요가 없습니다.
반면에, printf에 우선을 사용하여 정당화 할 수있는, 상당히 빠른 cout에서 매우 제한적인 특정 경우. 항상 먼저 프로파일하십시오. (예를 들어 http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout / 참조)
사람들은 종종 printf훨씬 빠르다고 주장합니다 . 이것은 대부분 신화입니다. 방금 테스트 한 결과는 다음과 같습니다.
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
결론 : 줄 바꿈 만 원하면 printf; 그렇지 않으면 cout거의 빠르거나 훨씬 빠릅니다. 자세한 내용은 내 블로그 에서 확인할 수 있습니다 .
분명히하기 위해 iostreams가 항상보다 낫다고 말하려고하지는 않습니다 printf. 나는 단지 일반적인 데이터를 바탕으로 정보에 근거한 결정을 내려야한다고 말하려고합니다.
업데이트 : 테스트에 사용한 전체 코드는 다음과 같습니다. g++추가 옵션없이 컴파일 -lrt합니다 (타이밍 제외).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
그리고 나는 인용한다 :
높은 수준의 용어의 주요 차이점은 유형 안전성 (cstdio에 없음), 성능 (대부분의 iostream 구현이 cstdio에 비해 느리다) 및 확장 성 (iostream은 사용자 정의 출력 대상 및 사용자 정의 유형의 원활한 출력 허용)입니다.
하나는 stdout으로 인쇄하는 기능입니다. 다른 하나는 여러 멤버 함수와 operator<<해당 인쇄의 과부하 를 stdout에 제공하는 객체입니다 . 열거 할 수있는 더 많은 차이점이 있지만, 당신이 무엇을하는지 잘 모르겠습니다.
나를 위해, 'printf'가 아닌 'cout'으로 갈 수있는 진정한 차이점은 다음과 같습니다.
1) << 연산자가 내 클래스에 과부하 될 수 있습니다.
2) cout의 출력 스트림을 파일로 쉽게 변경할 수 있습니다 : (: 복사 붙여 넣기 :)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) 특히 매개 변수가 많을 때 cout이 더 읽기 쉽습니다.
한 가지 문제 와 함께 cout서식 옵션입니다. 데이터 포맷팅 (정밀도, 정당성 등) printf이 더 쉽습니다.
여기에 언급되지 않은 두 가지 점이 중요하다고 생각합니다.
1) cout아직 STL을 사용하지 않는 경우 많은 수하물을 운송합니다. 객체 파일에 두 배 이상의 코드를 추가합니다 printf. 이것은에도 해당 string되며 이것이 내 문자열 라이브러리를 사용하는 주된 이유입니다.
2) cout과부하 된 <<연산자를 사용하므로 불행합니다. <<의도 한 목적으로 연산자를 사용하는 경우 혼동을 일으킬 수 있습니다 (왼쪽 시프트). 나는 개인적으로 의도 한 용도에 접하는 목적으로 운영자에게 과부하를 걸고 싶지 않습니다.
결론 : 이미 STL을 사용하고 있다면 cout(및 string)을 사용합니다. 그렇지 않으면 피하는 경향이 있습니다.
프리미티브를 사용하면 사용하는 것이 중요하지 않을 수 있습니다. 유용한 곳은 복잡한 객체를 출력하려고 할 때입니다.
예를 들어 수업이 있으면
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
위의 내용이 그다지 좋지는 않지만 코드의 여러 곳에서 이것을 출력해야한다고 가정 해 봅시다. 뿐만 아니라 "int d"필드를 추가한다고 가정 해 봅시다. cout을 사용하면 한 번만 변경하면됩니다. 그러나 printf를 사용하면 많은 곳에서 변경해야 할뿐만 아니라 출력 할 곳을 상기시켜야합니다.
cout을 사용하면 코드 유지 관리에 소요되는 시간을 크게 줄일 수 있으며 새 응용 프로그램에서 "Something"개체를 재사용 할 경우 출력에 대해 걱정할 필요가 없습니다.
물론 유지 보수를 유지하기 위해 "무언가"를 조금 더 잘 작성할 수 있습니다.
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
cout과 printf에 대한 약간의 확장 테스트는 더 많은 테스트를 원한다면 'double'테스트를 추가했습니다 (Visual Studio 2008, 릴리스 버전의 실행 파일).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
결과는 다음과 같습니다.
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
C ++에서 스레드로 재생하려면 사용 cout하면 흥미로운 결과를 얻을 수 있다고 지적하고 싶습니다 .
이 코드를 고려하십시오.
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
이제 출력이 모두 섞입니다. 다른 결과를 얻을 수도 있으므로 여러 번 실행하십시오.
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
당신이 사용할 수있는 printf것이 바로 얻기 위해, 또는 당신이 사용할 수 있습니다 mutex.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
즐기세요!
확장 성 부족이 printf완전히 사실이 아니라고 말하고 싶습니다
. C에서는 사실입니다. 그러나 C에는 실제 클래스가 없습니다.
C ++에서는 캐스트 연산자를 오버로드하여 char*연산자를 오버로드하고 다음 과 printf같이 사용할 수 있습니다.
Foo bar;
...;
printf("%s",bar);
Foo가 좋은 작업자에게 과부하가 걸리면 가능할 수 있습니다. 또는 좋은 방법을 만든 경우. 요컨대, 나 printf만큼 확장 cout할 수 있습니다.
C ++ 스트림 (일반적으로 cout뿐만 아니라)에 대해 볼 수있는 기술적 인 주장은 다음과 같습니다.
타입 안전. (그리고 그런데, 내가 하나를 인쇄
'\n'하려면 내가 사용하는putchar('\n')... 핵 폭탄을 사용하여 곤충을 죽이지 않을 것입니다.)배우기 더 간단합니다. (배우기위한 "복잡한"매개 변수 없음, 단지 사용
<<과>>연산자)기본적으로 워크
std::string(위해printf존재std::string::c_str()하지만,에scanf?)
를 들어 printfI 참조 :
더 복잡하거나 더 짧은 (작은 문자로) 복잡한 서식. 나에게 훨씬 더 읽기 쉽다 (맛이 나는 것 같다).
함수의 기능을보다 잘 제어 할 수 있습니다 (작성된 문자 수와
%n포맷터 가있는 경우 : "아무것도 인쇄되지 않습니다. 인수는 지금까지 작성된 문자 수가 저장되는 부호있는 int에 대한 포인터 여야합니다"( printf에서) -C ++ 레퍼런스 )더 나은 디버깅 가능성. 마지막 주장과 같은 이유로.
개인적으로 선호하는 기능은 주로 짧은 줄을 좋아하고 텍스트 인쇄시 유형 문제를 피하기 어렵다고 생각하기 때문에 printf(및 scanf) 기능으로 이동합니다 . C 스타일 함수로 내가 싫어하는 것은 std::string지원되지 않는다는 것입니다. 우리는 char*그것을주기 전에 겪어야 합니다 printf( std::string::c_str()읽기를 원한다면, 어떻게 쓰는가?)
더 많은 차이점 : "printf"는 정수 값 (인쇄 된 문자 수와 같음)을 반환하고 "cout"은 아무것도 반환하지 않습니다
과.
cout << "y = " << 7; 원자가 아닙니다.
printf("%s = %d", "y", 7); 원자입니다.
cout은 유형 검사를 수행하지만 printf는 수행하지 않습니다.
이에 상응하는 iostream이 없습니다 "% d"
TL; DR : 생성 된 머신 코드 크기 , 성능 , 가독성 및 코딩 시간 과 관련하여 항상 자신의 연구를 수행하십시오 .
난 전문가가 아니야 성능 문제로 인해 임베디드 시스템에서 C ++를 사용하지 않는 방법에 대해 이야기하는 두 명의 동료에 대해 방금 들었습니다. 글쎄, 흥미롭게도 실제 프로젝트 작업을 기반으로 벤치 마크를 수행했습니다.
이 작업에서는 RAM에 구성을 작성해야했습니다. 다음과 같은 것 :
커피 =
설탕 = 없음
우유 = 유방
맥 = AA : BB : CC : DD : EE : FF
여기 내 벤치 마크 프로그램이 있습니다 (예, OP는 fprintf ()가 아닌 printf ()에 대해 물었습니다. 본질을 포착하려고 노력하지만 OP의 링크는 fprintf ()를 가리 킵니다).
C 프로그램 :
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
C ++ 프로그램 :
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
나는 그들을 100,000 번 반복하기 전에 연마하기 위해 최선을 다했습니다. 결과는 다음과 같습니다.
C 프로그램 :
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
C ++ 프로그램 :
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
객체 파일 크기 :
C - 2,092 bytes
C++ - 3,272 bytes
결론 : 내 매우 구체적인에서 플랫폼 매우 구체적인와, 프로세서 의 매우 구체적인 버전 실행, 리눅스 커널 의 매우 구체적인 버전으로 컴파일 된 프로그램 실행, GCC를 매우 구체적인 달성하기 위해, 작업을 , 나는 말할 것 C ++ 접근 방식은 훨씬 더 빠르게 실행되고 훨씬 더 나은 가독성을 제공하기 때문에 더 적합합니다. 다른 한편으로, C는 작은 발자국을 제공한다고 생각하지만 프로그램 크기가 우리의 관심사가 아니기 때문에 거의 아무것도 의미하지 않습니다.
리 메버, YMMV.
저는 프로그래머는 아니지만 인적 요소 엔지니어였습니다. 프로그래밍 언어는 배우고 이해하고 사용하기 쉬워야한다고 생각합니다.이를 위해서는 간단하고 일관된 언어 구조가 필요합니다. 모든 언어가 상징적이므로 핵심적으로 임의적이지만 규칙을 따르고 따라 가면 언어를 배우고 사용하기가 더 쉬워집니다.
C ++에는 함수 전 (pre-computer) 시대의 수학에서 기능적 관계에 원래 사용되었던 구문 인 function (parameter)으로 작성된 다른 언어가 많이 있습니다. printf()이 구문을 따르고 C ++ 작성자가 파일을 읽고 쓰는 논리적으로 다른 방법을 만들고자한다면 비슷한 구문을 사용하여 다른 기능을 만들었을 수 있습니다.
파이썬에서는 물론 object.method변수는 객체이지만 C ++에서는 그렇지 않기 때문에 상당히 표준적인 구문, 즉 variablename.print를 사용하여 인쇄 할 수 있습니다 .
<< 연산자는 규칙을 따르지 않기 때문에 cout 구문을 좋아하지 않습니다. 메소드 또는 함수입니다. 즉, 매개 변수를 가져 와서 무언가를 수행합니다. 그러나 수학 비교 연산자 인 것처럼 작성되었습니다. 이것은 인적 요소 관점에서 볼 때 좋지 않은 접근법입니다.
cout<< "Hello";
printf("%s", "Hello");
둘 다 값을 인쇄하는 데 사용됩니다. 그것들은 완전히 다른 구문을 가지고 있습니다. C ++에는 둘 다 있고 C에는 printf 만 있습니다.
printfcout변수 이지만 함수 입니다.
참고 URL : https://stackoverflow.com/questions/2872543/printf-vs-cout-in-c
'development' 카테고리의 다른 글
| 특정 파일 만 숨기는 방법? (0) | 2020.03.03 |
|---|---|
| 경로가 파일인지 디렉토리인지 Node.js 확인 (0) | 2020.03.03 |
| 2 개의 GPS 좌표 사이의 거리 계산 (0) | 2020.03.03 |
| 동일한 시스템에서 Internet Explorer 6, Internet Explorer 7 및 Internet Explorer 8 실행 (0) | 2020.03.03 |
| python3.x에서 raw_input ()과 input ()의 차이점은 무엇입니까? (0) | 2020.03.03 |