내 C ++ 코드에서 printf를 사용해야합니까?
나는 일반적으로 사용 cout
하고 cerr
콘솔에 텍스트를 작성 할 수 있습니다. 그러나 때로는 좋은 오래된 printf
진술 을 사용하는 것이 더 쉽습니다 . 출력 형식을 지정해야 할 때 사용합니다.
이것을 사용하는 한 가지 예는 다음과 같습니다.
// Lets assume that I'm printing coordinates...
printf("(%d,%d)\n", x, y);
// To do the same thing as above using cout....
cout << "(" << x << "," << y << ")" << endl;
를 사용하여 출력을 형식화 할 수 있다는 것을 알고 cout
있지만 printf
. printf
성명서를 사용하지 말아야 할 이유가 있습니까?
배우 내 학생, cin
및 cout
첫째, 다음 학습 printf
압도적으로 선호 나중에 printf
(더 일반적으로 또는 fprintf
). 나는 printf
모델을 다른 프로그래밍 언어로 이식 할만큼 충분히 읽기 쉬운 모델 을 발견했습니다 . 그래서이 올리비에 댄비 심지어 입력 안전했다.
에 대한 유형 검사 호출이 가능한 컴파일러가 있다면 C ++에서 printf
사용하지 않을 이유가 없습니다 fprintf
.
면책 조항 : 저는 끔찍한 C ++ 프로그래머입니다.
프로그램을 i18n하고 싶다면 iostreams를 멀리하십시오. 문제는 문장이 iostream으로 수행되는 것처럼 여러 조각으로 구성된 경우 문자열을 올바르게 현지화하는 것이 불가능할 수 있다는 것입니다.
메시지 조각 문제 외에도 순서 문제도 있습니다. 학생의 이름과 평균 학점을 인쇄하는 보고서를 고려하십시오.
std::cout << name << " has a GPA of " << gpa << std::endl;
그것을 다른 언어로 번역 할 때, 다른 언어의 문법에서는 이름 앞에 GPA를 표시해야 할 수도 있습니다. AFAIK, iostreams는 보간 된 값을 재정렬 할 방법이 없습니다.
두 가지 장점 (유형 안전성 및 i18n 가능)을 모두 원한다면 Boost.Format을 사용 하십시오 .
적응성
printf
비 POD 에 대한 모든 시도 는 정의되지 않은 동작을 초래합니다.
struct Foo {
virtual ~Foo() {}
operator float() const { return 0.f; }
};
printf ("%f", Foo());
std::string foo;
printf ("%s", foo);
위의 printf 호출은 정의되지 않은 동작을 생성합니다. 컴파일러가 실제로 경고 할 수 있지만 이러한 경고는 표준에 의해 요구되지 않으며 런타임에만 알려진 형식 문자열에는 불가능합니다.
IO 스트림 :
std::cout << Foo();
std::string foo;
std::cout << foo;
스스로 판단하십시오.
확장 성
struct Person {
string first_name;
string second_name;
};
std::ostream& operator<< (std::ostream &os, Person const& p) {
return os << p.first_name << ", " << p.second_name;
}
cout << p;
cout << p;
some_file << p;
씨:
// inline everywhere
printf ("%s, %s", p.first_name, p.second_name);
printf ("%s, %s", p.first_name, p.second_name);
fprintf (some_file, "%s, %s", p.first_name, p.second_name);
또는:
// re-usable (not common in my experience)
int person_fprint(FILE *f, const Person *p) {
return fprintf(f, "%s, %s", p->first_name, p->second_name);
}
int person_print(const Person *p) {
return person_fprint(stdout, p);
}
Person p;
....
person_print(&p);
당신이 적절한 호출 인수 / C에 서명 (예를 들어, 사용 돌봐 얼마나 참고 person_fprint(stderr, ...
, person_fprint(myfile, ...
C ++에서 "), FILE
-argument"는 자동적으로는 표현에서 "파생". 이 파생의 더 정확한 등가물은 실제로 다음과 같습니다.
FILE *fout = stdout;
...
fprintf(fout, "Hello World!\n");
person_fprint(fout, ...);
fprintf(fout, "\n");
I18N
Person 정의를 재사용합니다.
cout << boost::format("Hello %1%") % p;
cout << boost::format("Na %1%, sei gegrüßt!") % p;
printf ("Hello %1$s, %2$s", p.first_name.c_str(), p.second_name.c_str());
printf ("Na %1$s, %2$s, sei gegrüßt!",
p.first_name.c_str(), p.second_name.c_str());
스스로 판단하십시오.
나는 이것이 오늘 (2017) 현재 관련성이 덜하다고 생각합니다. 그냥 직감 일 수도 있지만, I18N은 평범한 C 또는 C ++ 프로그래머가 매일하는 일이 아닙니다. 게다가, 그것은 어쨌든 해부학적인 고통입니다.
공연
- printf 성능의 실제 중요성을 측정 했습니까? 병목 응용 프로그램이 심각하게 게으 르기 때문에 계산 결과의 출력이 병목 상태입니까? C ++가 꼭 필요한가요?
- 두려운 성능 패널티는 printf와 cout을 혼합하여 사용하려는 사람들을 만족시키는 것입니다. 버그가 아니라 기능입니다!
iostreams를 지속적으로 사용하면 다음을 수행 할 수 있습니다.
std::ios::sync_with_stdio(false);
좋은 컴파일러로 동일한 런타임을 거두십시오.
#include <cstdio>
#include <iostream>
#include <ctime>
#include <fstream>
void ios_test (int n) {
for (int i=0; i<n; ++i) {
std::cout << "foobarfrob" << i;
}
}
void c_test (int n) {
for (int i=0; i<n; ++i) {
printf ("foobarfrob%d", i);
}
}
int main () {
const clock_t a_start = clock();
ios_test (10024*1024);
const double a = (clock() - a_start) / double(CLOCKS_PER_SEC);
const clock_t p_start = clock();
c_test (10024*1024);
const double p = (clock() - p_start) / double(CLOCKS_PER_SEC);
std::ios::sync_with_stdio(false);
const clock_t b_start = clock();
ios_test (10024*1024);
const double b = (clock() - b_start) / double(CLOCKS_PER_SEC);
std::ofstream res ("RESULTS");
res << "C ..............: " << p << " sec\n"
<< "C++, sync with C: " << a << " sec\n"
<< "C++, non-sync ..: " << b << " sec\n";
}
결과 ( g++ -O3 synced-unsynced-printf.cc
, ./a.out > /dev/null
, cat RESULTS
) :
C ..............: 1.1 sec
C++, sync with C: 1.76 sec
C++, non-sync ..: 1.01 sec
판사 ...
아니, 당신은 내 지문을 금지하지 않을 것입니다.
가변 템플릿 덕분에 C ++ 11에서 typesafe, I18N 친화적 인 printf를 사용할 수 있습니다. 그리고 사용자 정의 리터럴을 사용하여 매우 뛰어난 성능을 발휘할 수 있습니다. 즉, 완전히 정적 인 화신을 작성할 수 있습니다.
개념 증명이 있습니다. 당시 C ++ 11에 대한 지원은 지금만큼 성숙하지는 않았지만 아이디어를 얻었습니다.
시간적 적응성
// foo.h
...
struct Frob {
unsigned int x;
};
...
// alpha.cpp
... printf ("%u", frob.x); ...
// bravo.cpp
... printf ("%u", frob.x); ...
// charlie.cpp
... printf ("%u", frob.x); ...
// delta.cpp
... printf ("%u", frob.x); ...
나중에 데이터가 너무 커져서해야 할 일
// foo.h
...
unsigned long long x;
...
그것을 유지하고 버그없이하는 것은 흥미로운 운동입니다. 특히 결합되지 않은 다른 프로젝트에서 foo.h를 사용하는 경우 특히 그렇습니다 .
다른.
버그 가능성 : 특히 사용자 입력 기반 문자열을 믹스에 던질 때 printf에 실수를 저지를 공간이 많이 있습니다 (I18N 팀을 생각하십시오). 이러한 모든 형식 문자열을 적절하게 이스케이프 처리해야하며 올바른 인수 등을 전달해야합니다.
IO-Streams는 내 바이너리를 더 크게 만듭니다 . 이것이 유지 보수성, 코드 품질, 재사용 성보다 더 중요한 문제인 경우 (문제를 확인한 후!) printf를 사용하십시오.
나는 추악한 <<cout<<
구문을 싫어하기 때문에 printf를 사용 합니다.
boost :: format을 사용하십시오. 타입 안전성, std :: string 지원, 인터페이스와 같은 printf, cout 사용 능력 및 기타 많은 좋은 것들을 얻을 수 있습니다. 당신은 돌아 가지 않을 것입니다.
전혀 이유가 없습니다. 좋은 오래된 C 라이브러리가 여전히 유효하지만 사람들이 C ++ 라이브러리 만 사용하도록 유도하는 것은 이상한 이념이라고 생각합니다. 저는 C ++ 사람이고 C 함수도 많이 사용합니다. 그들과 아무런 문제가 없었습니다.
스트림은 표준 방식입니다. 이 코드가 printf
다음 과 같이 작동하도록하십시오 .
template <typename T>
void output(const T& pX)
{
std::cout << pX << std::endl;
}
행운을 빕니다.
내 말은, 당신의 타입이 ostream
's 로 출력되도록 연산자를 만들 수 있고 , 다른 타입과 마찬가지로 번거 로움없이 사용할 수 있다는 것입니다. printf
C ++의 일반성 또는보다 구체적으로 템플릿에 맞지 않습니다.
유용성 그 이상이 있습니다. 일관성도 있습니다. 내 모든 프로젝트에서 파일로 출력 할 수있는 cout (및 cerr
및 clog
)이 있습니다. 을 사용 printf
하면 모든 것을 건너 뜁니다. 또한 일관성 자체가 좋은 것입니다. 혼합 cout
과 printf
완벽하게 유효한 동안, 추악한입니다.
객체가 있고이를 출력 가능하게 만들고 싶다면 가장 깔끔한 방법 operator<<
은 해당 클래스에 대한 오버로드 입니다. 그럼 어떻게 사용할 printf
건가요? 당신은 cout
's와 printf
's로 뒤섞인 코드로 끝날 것입니다 .
정말로 포맷을 원한다면 스트림 인터페이스를 유지하면서 Boost.Format을 사용하십시오. 일관성 및 서식.
printf를 사용하십시오. C ++ 스트림을 사용하지 마십시오. printf는 훨씬 더 나은 제어를 제공합니다 (예 : 부동 소수점 정밀도 등). 코드는 일반적으로 더 짧고 읽기 쉽습니다.
Google C ++ 스타일 가이드에 동의합니다.
로깅 인터페이스에 필요한 경우를 제외하고는 스트림을 사용하지 마십시오. 대신 printf와 유사한 루틴을 사용하십시오.
스트림 사용에는 다양한 장단점이 있지만이 경우에는 다른 많은 경우와 마찬가지로 일관성이 논쟁을 능가합니다. 코드에서 스트림을 사용하지 마십시오.
전반적으로 동의합니다 (특히 복잡한 서식이 필요한 경우 << 구문을 싫어합니다)
그러나 나는 안전 측면을 지적해야한다.
printf("%x",2.0f)
printf("%x %x",2)
printf("%x",2,2)
아마도 컴파일러가 알아 차리지 못하지만 앱이 충돌 할 수 있습니다.
필요와 선호도에 맞는 것을 사용하십시오. printf에 익숙하다면 반드시 그것을 사용하십시오. 당신이 iostreams에 더 만족한다면 그들을 고수하십시오. 요구 사항에 가장 잘 맞는 믹스 앤 매치. 결국 이것은 소프트웨어입니다. 더 좋은 방법과 더 나쁜 방법이 있지만 한 가지 방법 만있는 경우는 거의 없습니다.
공유하고 즐기십시오.
나는 printf를 좋아하지 않는다. 형식 안전성이 없기 때문에 사용이 위험 할뿐만 아니라 형식 지정자를 기억해야하는 것도 고통 스럽습니다. 현명하게 올바른 일을하는 템플릿 연산자가 훨씬 낫습니다. 그래서 저는 항상 C ++에서 C ++ 스트림을 사용합니다.
물론, 많은 사람들은 다른 이유로 다른 곳에 열거 된 printf를 선호합니다 .
나는 종종를 사용하는 것으로 "되돌려 놓는다" printf()
. 그러나 더 snprintf()
쉬운 형식의 출력을 위해 더 자주 사용 합니다. C ++로 프로그래밍 할 때이 래퍼를 사용하여 잠시 전에 다음과 같이 썼습니다 (위와 같이 예제를 사용하기 위해).cout << format("(%d,%d)\n", x, y);
헤더 ( stdiomm.h
) 는 다음과 같습니다 .
#pragma once
#include <cstdarg>
#include <string>
template <typename T>
std::basic_string<T> format(T const *format, ...);
template <typename T>
std::basic_string<T> vformat(T const *format, va_list args);
소스 ( stdiomm.cpp
) :
#include "stdiomm.h"
#include <boost/scoped_array.hpp>
#include <cstdio>
template <>
std::wstring vformat(wchar_t const *format, va_list arguments)
{
#if defined(_WIN32)
int required(_vscwprintf(format, arguments));
assert(required >= 0);
boost::scoped_array<wchar_t> buffer(new wchar_t[required + 1]);
int written(vswprintf(buffer.get(), required + 1, format, arguments));
assert(written == required);
return std::wstring(buffer.get(), written);
#else
# error "No implementation yet"
#endif
}
template <>
std::string vformat(char const *format, va_list arguments)
{
#if defined(_WIN32)
int required(_vscprintf(format, arguments));
assert(required >= 0);
boost::scoped_array<char> buffer(new char[required + 1]);
int written(vsnprintf(buffer.get(), required + 1, format, arguments));
assert(written == required);
return std::string(buffer.get(), written);
#else
char *buffer;
int printed = vasprintf(&buffer, format, arguments);
assert(printed != -1);
std::string retval(buffer, printed);
free(buffer);
return retval;
#endif
}
template <typename T>
std::basic_string<T> format(T const *format, ...)
{
va_list ap;
va_start(ap, format);
std::basic_string<T> retval(vformat(format, ap));
va_end(ap);
return retval;
}
template std::wstring format(wchar_t const *format, ...);
template std::string format(char const *format, ...);
최신 정보
다른 답변을 읽은 후 boost::format()
나 자신 으로 전환해야 할 수도 있습니다 !
질문이 다소 오래되었지만 2 센트를 더하고 싶습니다.
사용자가 만든 객체를 printf ()로 인쇄하기
생각해 보면 다소 간단합니다. 유형을 문자열 화하고 문자열을 printf로 보낼 수 있습니다.
std::string to_string(const MyClass &x)
{
return to_string(x.first)+" "+to_string(x.second);
}
//...
printf("%s is awesome", to_string(my_object).c_str()); //more or less
객체를 문자열 화하는 표준 C ++ 인터페이스가 없었습니다 (C ++ 11 to_string ()).
printf () 함정
단일 플래그-% n
The only one that is an output parameter - it expects pointer to int. It writes number of succesfully written characters to location pointed by this pointer. Skillful use of it can trigger overrun, which is security vulnerability (see printf() format string attack).
You can get the best of both worlds with the fmt library which combines safety and extensibility of iostreams with usability and performance of (s)printf
. Example:
std::string = fmt::format("The answer is {}", 42);
The library supports Python-like and printf format string syntax.
Disclaimer: I'm the author of the fmt library.
I almost always use printf for temporary debugging statements. For more permanent code, I prefer the 'c' streams as they are The C++ Way. Although boost::format looks promising and might replace my stream usage (especially for complexly formatted output), probably nothing will replace printf for me for a long time.
C++ streams are overrated, after all they're in fact just classes with an overloaded operator <<
.
I've read many times that streams are the C++ way as printf is the C way, but they are both library features available in C++, so you should use what suits best.
I mostly prefer printf, but I've also used streams, which provide cleaner code and prevent you from having to match % placeholders to arguments.
It depends on the situation. Nothing is perfect. I use both. Streams are good for custom types as you can overload the >> operator in ostream. But when it comes to spacing and etc it's better to use printf(). stringstream and like are better than the C style strcat(). So use one that's appropriate for the situation.
I have read warnings saying that cout and cerr are unsafe for multithreading. If true, this is a good reason to avoid using them. Note: I use GNU g++ with openMP.
streams are preferred in cpp as they adhere to the object oriented paradigm of cpp, beside being type safe.
printf , on the other hand is more of a functional approach.
only reason for not using printf in cpp code that i can think of is not being object oriented.
its more of a personal choice.
참고URL : https://stackoverflow.com/questions/2017489/should-i-use-printf-in-my-c-code
'Program Tip' 카테고리의 다른 글
두 날짜의 날짜 정보가 동일한 지 확인 (0) | 2020.11.09 |
---|---|
Rails의 link_to 본문에 포함 된 HTML (0) | 2020.11.09 |
클래스없이 특정 요소를 얻기 위해 jQuery : not 및 hasClass ()에서 사용하는 방법 (0) | 2020.11.09 |
jQuery Keypress 화살표 키 (0) | 2020.11.09 |
Devise로 사용자를 "소프트 삭제"하는 방법 (0) | 2020.11.09 |