How does C++ interpret a cout with a '+' in it?
Asked Answered
G

5

27

I've been moving back and forth with Java/C++ so I messed up with my console output and accidentally wrote lines like:

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

Each of which gave me bits and pieces of other strings I had in my program. I realize my mistake now, but what was C++ interpreting those lines as so that they output different parts of different strings in my program?

Giraud answered 17/4, 2015 at 22:14 Comment(6)
The cout is irrelevant here. What are the types of numSamples and maxSampleValue? ints?Railroader
Try a longer string and use 0, 1, 2, etc instead of your variables.Corduroys
That you're asking about cout indicates a misunderstanding about the language. cout isn't a keyword, and it's not magical. It's an ordinary object. cout is fed the result of "num" + numSamples; it has way of knowing that the original expression contained a + in it.Roughandtumble
Depending on your compiler, you could have used "num"s + numSamples (with a using for the appropriate namespace) and got exactly what you expected, by the way.Simonetta
@Roughandtumble I think operator<< contributes to this confusion for newcomers as well. It's easy really - "look! Just a function call! operator<<( operator<<(cout, "num"+numsamples), endl );"Avis
(Oops, I meant to write: "it has no way of knowing...")Roughandtumble
H
36

There is a simple reason for this:

"num" and "max" are string literal. Their type is const char *. Assuming numSamples is an integer, what you are doing is is pointer arithmetic.

You are basically printing a string that points to "num" + numSamples bytes.

If you did cout << "num" + 1 << endl this would print "um".

You probably figured it out, but the correct way to do this is: cout << "num" << numSamples << endl;

Also, you asked:

But what was C++ interpreting those lines as so that they output different parts of different strings in my program?

As stated before, "num" is a string literal. Generally string literals sits in the same place in the binary program: .rodata. All other string literals sits in this region, so when you are advancing your pointer by a certain amount of bytes, you will likely points to some other string literals, thus printing (part of) them.

Hagiolatry answered 17/4, 2015 at 22:18 Comment(2)
The string literals have a type of const char(&)[4], which decays to a const char* sometimes, including this situation.Satellite
@MooingDuck They are lvalues of type const char [4]. No &.Kestrel
P
30

It is just pointer arithmetic. For instance,

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

would print a string staring from ((address of)"num" + 1), i.e. "um".

If the value we add exceeds the length of the string, then we have undefined behavior.

Poem answered 17/4, 2015 at 22:17 Comment(0)
H
3

Keep in mind that although iostreams overload << (and >>) to do I/O, these were originally defined as bit-shift operators. When the compiler's parsing the expression, it's basically seeing "operand, operator, operand", then checking whether the operands are of types to which that operator can be applied.

In this case, we have a string literal and (apparently) some sort of integer, and the compiler knows how to do math on those (after converting the string literal to a pointer).

From the compiler's viewpoint, however, this isn't a whole lot different from something like:

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

a = b << c + d;

The difference is that with operands of type int, the meaning is fairly obvious: it's doing addition and bit-shifting. With iostreams, the meaning attached to << and >> change, but the syntax allowed for them in an expression is unchanged.

From the compiler's "viewpoint" the only question is whether the operands to + are of types for which + is allowed--in this case, you have pointer to char + integer, so that's allowed. The result is a pointer to char, and it has an overload of << that takes a left-hand operand of type ostream and a right-hand operator of type pointer to char, so the expression as a whole is fine (as far as it cares).

Haematogenous answered 17/4, 2015 at 22:38 Comment(0)
G
2

"num" type is char const [4]. If numSamples is integer, "num" + numSamples type is const char *. So you call operator << cor std::cout, that overloaded for const char * and prints string that starts from address addres("num") + numSamples in pointer arithmetic.

Try this:

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

std::to_string() function you can find in <string>

Gradus answered 17/4, 2015 at 22:17 Comment(1)
This does not answer the question.Juju
G
2

if you look at operator_precedence, you will see that + gets evaluated before <<, which leaves this expression to be evaluated before being passed to the operator <<:

"num" + numSamples

Now "num" is going to be a static const char * and I'm assuming numSamples is an integral type. Since the left-hand side of the + is a pointer type and you are adding to it, that's pointer arithmetic. The cout now gets a pointer to a location in memory that is numSamples or maxSamplueValue more than the location of "num" or "max". Most likely all of your static strings were lined up in in the same region of memory which is why you saw them rather than random gibberish.

Geanticlinal answered 17/4, 2015 at 22:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.