2015-04-17 8 views
27

Ich habe hin und her mit Java/C bewegt ++ so verwirrte ich mit meiner Konsole ausgegeben und versehentlich Zeilen wie schrieb:Wie interpretiert C++ einen Cout mit einem '+' darin?

cout << "num" + numSamples << endl; 
cout << "max" + maxSampleValue << endl; 

meine Jeder von denen hat mir Stücke von anderen Saiten, die ich hatte in Programm. Ich begreife jetzt meinen Fehler, aber wie interpretierte C++ diese Zeilen so, dass sie unterschiedliche Teile verschiedener Zeichenketten in meinem Programm ausgeben?

+5

Der 'cout' ist hier irrelevant. Was sind die Arten von 'numSamples' und' maxSampleValue'? 'Int's? – BoBTFish

+2

Versuchen Sie eine längere Zeichenfolge und verwenden Sie 0, 1, 2 usw. anstelle Ihrer Variablen. – molbdnilo

+2

Dass Sie nach 'cout' fragen, deutet auf ein Missverständnis der Sprache hin. "Cout" ist kein Schlüsselwort, und es ist nicht magisch. Es ist ein gewöhnliches Objekt. 'cout' wird mit dem * Ergebnis * von' "num" + numSamples' gespeist; es hat eine Art zu wissen, dass der ursprüngliche Ausdruck ein "+" darin enthielt. – jamesdlin

Antwort

36

Es gibt einen einfachen Grund:

"num" und "max" sind Stringliteral. Ihr Typ ist const char *. Angenommen numSamples ist eine ganze Zahl, was Sie tun, ist Zeiger Arithmetik.

Sie drucken grundsätzlich eine Zeichenfolge, die auf "num" + numSamples Bytes zeigt.

Wenn Sie cout << "num" + 1 << endl getan hätten, würde dies "um" drucken.

Sie dachten, dass es wahrscheinlich, aber der richtige Weg, dies zu tun ist: cout << "num" << numSamples << endl;

Auch Sie fragte:

Aber was war C++ diese Zeilen zu interpretieren als so, dass sie Ausgangs verschiedenen Teilen von verschiedenen Saiten in meinem Programm?

Wie bereits erwähnt, ist "num" ein String-Literal. Im Allgemeinen befinden sich String-Literale an derselben Stelle im Binärprogramm: .rodata. Alle anderen Zeichenfolgenliterale befinden sich in dieser Region. Wenn Sie also Ihren Zeiger um eine bestimmte Anzahl von Bytes weiterleiten, werden Sie wahrscheinlich auf einige andere Zeichenfolgenliterale verweisen und diese (teilweise) drucken.

+6

Die String-Literale haben einen Typ von 'const char (&) [4]', der _decays_ zu einem 'const char *' manchmal, einschließlich dieser Situation. –

+7

@MooingDuck Sie sind Lvalues ​​vom Typ 'const char [4]'. Nein '&'. –

2

"num" Typ ist char const [4]. Wenn numSamples eine Ganzzahl ist, ist "num" + numSamples der Typ const char *. So rufen Sie operator << cor std::cout, dass für const char * überlastet und druckt Zeichenfolge, die von Adresse Adressen ("num") + numSamples in Zeigerarithmetik beginnt.

Try this:

cout << "num" + std::to_string(numSamples) << endl; 
cout << "max" + std::to_string(maxSampleValue) << endl; 

std::to_string() Funktion, die Sie finden in <string>

+0

Dies beantwortet die Frage nicht. – nico

30

Es ist nur arithmetische Zeiger. Zum Beispiel

cout << "num" + 1 << endl; 

würde eine Zeichenfolge aus ((address of)"num" + 1) starren drucken, das heißt "um".

Wenn der Wert, den wir hinzufügen, die Länge der Zeichenfolge überschreitet, haben wir ein undefiniertes Verhalten.

3

Denken Sie daran, dass, obwohl Iostreams << (und >>) I/O überlasten, diese ursprünglich als Bit-Shift-Operatoren definiert wurden.Wenn der Compiler den Ausdruck analysiert, sieht er im Grunde "Operand, Operator, Operand" und prüft dann, ob die Operanden von Typen sind, auf die dieser Operator angewendet werden kann.

In diesem Fall haben wir ein String-Literal und (scheinbar) irgendeine Art von Integer, und der Compiler weiß, wie man diese Berechnungen durchführt (nach der Umwandlung des String-Literals in einen Zeiger).

Aus Sicht der Compiler, jedoch ist dies nicht viel anders als so etwas wie:

int a, b=1, c=2, d = 3; 

a = b << c + d; 

Der Unterschied besteht darin, dass mit Operanden vom Typ int, die Bedeutung ziemlich offensichtlich ist: es tut hinaus und Bit-Verschiebung. Bei Iostreams ändert sich die Bedeutung, die an << und >> angefügt ist, aber die für sie in einem Ausdruck zulässige Syntax ist unverändert.

aus der „Sicht“ des Compilers ist die einzige Frage, ob die Operanden zu + von Typen sind für die + erlaubt ist - in diesem Fall Sie pointer to char + integer haben, so dass erlaubt ist. Das Ergebnis ist ein Zeiger auf char, und es hat eine Überladung von <<, die einen linken Operanden vom Typ ostream und einen rechten Operator vom Typ pointer to char nimmt, so dass der Ausdruck als Ganzes in Ordnung ist (so weit es ihn interessiert) .

2

wenn man sich operator_precedence schauen, sehen Sie, dass + vor << ausgewertet wird, die diesen Ausdruck, bevor zu bewerten lässt dem Bediener << geleitet wird:

"num" + numSamples 

Jetzt "num" wird ein static const char * sein und ich nehme an, numSamples ist ein integraler Typ. Da die linke Seite der + ein Zeigertyp ist und Sie hinzufügen, das ist Zeigerarithmetik. Der Cout erhält jetzt einen Zeiger auf einen Speicherort im Speicher, der numSamples oder maxSamplueValue mehr als die Position "num" oder "max" ist. Höchstwahrscheinlich waren alle Ihre statischen Strings in der gleichen Region der Erinnerung aufgereiht, weshalb Sie sie eher als zufälliges Kauderwelsch gesehen haben.