IT박스

이 코드 스 니펫에서 cout이“2 + 3 = 15”를 인쇄하는 이유는 무엇입니까?

itboxs 2020. 7. 8. 08:06
반응형

이 코드 스 니펫에서 cout이“2 + 3 = 15”를 인쇄하는 이유는 무엇입니까?


왜 아래 프로그램의 출력이 무엇입니까?

#include <iostream>
using namespace std;

int main(){

    cout << "2+3 = " <<
    cout << 2 + 3 << endl;
}

생산

2+3 = 15

예상 대신

2+3 = 5

이 질문은 이미 여러 개의 닫기 / 다시 열기 주기로 진행되었습니다.

마감 투표에 앞서이 문제 에 대한 메타 토론을 고려 하십시오 .


의도적이든 우발적이든 <<, 첫 번째 출력 라인의 끝에 있습니다 ;. 그래서 당신은 본질적으로

cout << "2+3 = ";  // this, of course, prints "2+3 = "
cout << cout;      // this prints "1"
cout << 2 + 3;     // this prints "5"
cout << endl;      // this finishes the line

따라서 질문은 다음과 같이 요약됩니다. 왜 cout << cout;인쇄 "1"합니까?

이것은 아마도 놀랍게도 미묘한 것으로 판명되었습니다. std::cout는 기본 클래스를 통해 부울 컨텍스트에서 사용되는 특정 유형 변환 연산자std::basic_ios제공합니다 .

while (cout) { PrintSomething(cout); }

이것은 출력을 실패하기가 어렵 기 때문에 매우 좋지 않은 예입니다. 그러나 std::basic_ios실제로 입력 및 출력 스트림 모두의 기본 클래스이며 입력의 경우 훨씬 더 의미가 있습니다.

int value;
while (cin >> value) { DoSomethingWith(value); }

(스트림 끝에서 또는 스트림 문자가 유효한 정수를 형성하지 않을 때 루프에서 빠져 나옵니다).

이제이 변환 연산자의 정확한 정의가 표준의 C ++ 03과 C ++ 11 버전간에 변경되었습니다. 이전 버전에서는 operator void*() const;(일반적으로로 구현 됨 return fail() ? NULL : this;) 최신 버전에서는 explicit operator bool() const;(일반적으로 간단히 구현 됨 return !fail();)입니다. 두 선언 모두 부울 컨텍스트에서 제대로 작동하지만 이러한 컨텍스트 외부에서 사용되는 경우 다르게 동작합니다.

특히 C ++ 03 규칙에 따라 일부 주소 cout << cout로 해석 cout << cout.operator void*()되고 인쇄됩니다. C ++ 11 규칙에서는 cout << cout연산자가 선언 explicit되어 암시 적 변환에 참여할 수 없으므로 전혀 컴파일하지 않아야합니다 . 그것은 실제로 변화에 대한 주된 동기였으며, 무의미한 코드가 컴파일되는 것을 막았습니다. 어느 표준이든 준수하는 컴파일러는 인쇄하는 프로그램을 생성하지 않습니다 "1".

분명히 특정 C ++ 구현에서는 컴파일러와 라이브러리를 부적합한 결과를 생성하는 방식으로 혼합하고 일치시킬 수 있습니다 (@StephanLechner 인용 : "xcode에서 1을 생성하는 설정과 주소를 생성하는 다른 설정을 찾았습니다) : Language dialect "표준 라이브러리 libc ++ (c ++ 11을 지원하는 LLVM 표준 라이브러리)"와 결합 된 c ++ 98은 1을 생성하는 반면 libstdc (gnu c ++ 표준 라이브러리)와 결합 된 c ++ 98은 주소를 생성합니다. "). explicit변환을로 정의하는 C ++ 11 스타일 라이브러리와 결합 된 변환 연산자 (C ++ 11의 새로운 기능)를 이해하지 못하는 C ++ 03 스타일 컴파일러를 사용할 수 있습니다 operator bool(). 이러한 혼합을 통해 다음과 cout << cout같이 해석되어 cout << cout.operator bool()간단하게 cout << true인쇄 할 수있게 "1"됩니다.


Igor가 말했듯이 C ++ 11 라이브러리 std::basic_ios를 사용하면이 operator bool대신을 가지고 operator void*있지만 어떻게 든 선언되지 않습니다 (또는로 취급) explicit. 올바른 선언 여기참조 하십시오 .

예를 들어, 적합한 C ++ 11 컴파일러는 다음과 같은 결과를 제공합니다.

#include <iostream>
using namespace std;

int main() {
    cout << "2+3 = " << 
    static_cast<bool>(cout) << 2 + 3 << endl;
}

그러나 귀하의 경우 static_cast<bool>에는 묵시적 변환으로 (잘못) 허용됩니다.


편집 : 이것은 일반적이지 않거나 예상되는 동작이 아니므로 플랫폼, 컴파일러 버전 등을 아는 것이 유용 할 수 있습니다.


편집 2 : 참고로 코드는 일반적으로 다음과 같이 작성됩니다.

    cout << "2+3 = "
         << 2 + 3 << endl;

또는

    cout << "2+3 = ";
    cout << 2 + 3 << endl;

버그를 노출시키는 두 가지 스타일을 혼합하고 있습니다.


예기치 않은 출력의 이유는 오타입니다. 당신은 아마 의미

cout << "2+3 = "
     << 2 + 3 << endl;

출력이 예상되는 문자열을 무시하면 다음과 같이 남습니다.

cout << cout;

Since C++11, this is ill-formed. std::cout is not implicitly convertible to anything that std::basic_ostream<char>::operator<< (or a non member overload) would accept. Therefore a standards conforming compiler must at least warn you for doing this. My compiler refused to compile your program.

std::cout would be convertible to bool, and the bool overload of the stream input operator would have the observed output of 1. However, that overload is explicit, so it shouldn't allow an implicit conversion. It appears that your compiler/standard library implementation doesn't strictly conform to the standard.

In a pre-C++11 standard, this is well formed. Back then std::cout had an implicit conversion operator to void* which has a stream input operator overload. The output for that would however be different. it would print the memory address of the std::cout object.


The posted code should not compile for any C++11 (or later conformant compiler), but it should compile without even a warning on pre C++11 implementations.

The difference is that C++11 made the convertion of a stream to a bool explicit:

C.2.15 Clause 27: Input/output library [diff.cpp03.input.output] 27.7.2.1.3, 27.7.3.4, 27.5.5.4

Change: Specify use of explicit in existing boolean conversion operators
Rationale: Clarify intentions, avoid workarounds.
Effect on original feature: Valid C++ 2003 code that relies on implicit boolean conversions will fail to compile with this International Standard. Such conversions occur in the following conditions:

  • passing a value to a function that takes an argument of type bool;
    ...

ostream operator << is defined with a bool parameter. As a conversion to bool existed (and was not explicit) is pre-C++11, cout << cout was translated to cout << true which yields 1.

And according to C.2.15, this should not longer compile starting with C++11.


You can easily debug your code this way. When you use cout your output is buffered so you can analyse it like this:

Imagine first occurence of cout represents the buffer and operator << represents appending to the end of the buffer. Result of operator << is output stream, in your case cout. You start from:

cout << "2+3 = " << cout << 2 + 3 << endl;

After applying the above stated rules you get a set of actions like this:

buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

As I said before the result of buffer.append() is buffer. At the begining your buffer is empty and you have the following statement to process:

statement: buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);

buffer: empty

First you have buffer.append("2+3 = ") which puts the given string directly into the buffer and becomes buffer. Now your state looks like this:

statement: buffer.append(cout).append(2 + 3).append(endl);

buffer: 2+3 = 

After that you continue to analyze your statement and you come across cout as argument to append to the end of buffer. The cout is treated as 1 so you will append 1 to the end of your buffer. Now you are in this state:

statement: buffer.append(2 + 3).append(endl);

buffer: 2+3 = 1

Next thing you have in buffer is 2 + 3 and since addition has higher precedence than output operator you will first add these two numbers and then you will put the result in buffer. After that you get:

statement: buffer.append(endl);

buffer: 2+3 = 15

Finally you add value of endl to the end of the buffer and you have:

statement:

buffer: 2+3 = 15\n

After this process the characters from the buffer are printed from the buffer to standard output one by one. So the result of your code is 2+3 = 15. If you look at this you get additional 1 from cout you tried to print. By removing << cout from your statement you will get the desired output.

참고URL : https://stackoverflow.com/questions/41745877/why-does-cout-print-2-3-15-in-this-snippet-of-code

반응형