New to c++, know the use of << in e.g:
cout<<"hi";
but the following:
int a = 1<<3;
cout<<a;
will output 8; why is this I simply ask? How to I interpret the use of << here?
The << operator performs a bitshift when applied to integers.
1 in binary is 00000001. Shift it by three bits and you get 00001000, which is 8.
<< in 1<<3 is bit-wise left shift operator not a stream insertion. It will shift 1 to left by three bits.
The operation that every particular operator does and the result of that operation depends on what kind of type/object stands on its left and right side, so expect different results for different objects. As already explained, in this case it does a bitshift, because that is the operation defined for this operator, when both left and right elements are ints. In case of
cout<<"hi";
you have an std::ostream type on the left, and the std::string type on the right, and that is why the result of this operation is different - '<<' is in this case defined as an insertion operator; in case of two ints it is defined as a bit shift operator.
int a = 1<<3;
This is the "real" << operator. It performs bit-shifting. You normally do not need such an operation in high-level code; it dates back to the old days, long before C++ existed, when there was only C and when programmers had to manually tinker with such things much more frequently than in today's world.
In order to understand what's going on, you need to know how binary numbers work.
A decimal 1 remains, coincidentally, the same in binary:
1
Now picture some zeroes in front of it (this usually makes it easier to understand for beginners -- leading zeroes do not change a number's meaning, neither in decimal nor in binary):
...00000001
The << operation moves the bit to the left:
moved by 3 positions
+--+
| |
v |
...00001000
Now remove the leading zeroes:
1000
Here we go. Binary 1000 is 8 in decimal (1*8 + 0*4 + 0*2 + 0*1). For details and interesting corner cases, consult any good C++ book or online tutorial.
Now let's look at the other meaning of << in C++:
cout<<"hi";
This is an overloaded operator. C++ allows you to take almost any built-in operator and give it a new meaning for different classes. The language's standard library does exactly that with std::ostream (of which std::cout is an instance). The meaning does not have anything to do with bit-shifting anymore. It roughly means "output".
Nowadays, it is considered bad programming style to take an operator and give it a meaning completely unrelated to its original one. Examples for accepted use of operator overloading are when the new meaning makes sense with the original semantics, e.g. when you overload + or - for mathematical matrix classes. However, when C++ was invented, this feature was apparently used more liberally.
This is why we are stuck with the completely different meaning of << (and >>) today. In fact, the new semantics even seem to overshadow the original one for quite many beginners (as evidenced by your question).
Related
In many codes, people are using left shift to accomplish the multiplication. For example, 3 * i, some people prefer to use i << 1 + i, is there any benefit over the common one by using left shift.
One reason that jumps to my mind is to make the point that bitwise operations are being performed; The code can become a lot cleaner and intentions clearer with this style of notation than using hex (matter of opinion).
For example - to make the point that the 3rd bit is being set an engineer might do
uint32 foo = 1 << 3;
Note that in this case, the compiler will optimize this away completely and replace with an assign of 0x08; but the intent of 3rd bit being set is very clear.
This has a lot of use in embedded programming, encryption and other bit specific twiddling that don't jump to my mind.
It is not for performance optimizations, since the compiler can be expected to optimize a multiply by 2 to a shift it's not any faster; and in any case you'd be unlikely to notice the gains in most applications.
Your example however, 3*i being replaced by i << 1+i is poor since they are not the same operation.
According to this question (that is, OP stated the belief and was not corrected) - chained operators grow to the left:
a << b << c << d;
// ==
operator<<( operator<<( operator<<(a, b), c ), d);
Why is this the case? Would it not be more efficient to do:
operator<<( operator<<(a, b), operator<<(c, d) );
i.e., to balance as much as possible?
Surely the compiler could figure this out for better runtime performance?
When you overload an operator in C++, it retains the same precedence and associativity that operator has when it's not overloaded.
In the case of shift operators (<< and >>) the standard requires that:
The shift operators << and >> group left-to-right.
That means an operation like a<<b<<c must be parsed as (a<<b)<<c.
Overloading the operator changes the code that's invoked for each of those operations, but has no effect on grouping--the grouping will be the same whether a, b and c are of built-in types (e.g., int) for which the compiler-provided operator will be used, or whether they're some class type for which an overloaded operator will be used. The parser that handles the grouping remains identical either way.
Note, however, that order of evaluation is independent of precedence or associativity, so this does not necessarily affect execution speed.
Figuring this out for "better runtime performance" is better served by turning turning operations into CISC. (MULADDs for example.)
The synchronization cost between two processors would far outweigh the benefits for any reasonable number of operators that were crammed into one line.
This would render out-of-order processing impossible effectively making each core operate at the speed of a Pentium Pro.
Aside from the std::cout mentioned by Mystical, think of the following integer arithmetic problem: 3 * 5 / 2 * 4 that should result in (15 / 2) * 4, meaning 28, but if split out it would result in 15 / 8, meaning 1. This is true even though the operators have the same significance.
EDIT:
It's easy to think that we could get away with splitting commutative operations across cores, for example 3 * 5 * 2 * 4.
Now lets consider that the only way to communicate between cores is through shared memory. And that the average load time is an order of magnitude slower than the average CPU operation time. That alone means that a tremendous number of mathematical operations would need to be done before even accommodating 1 load would make sense. But even worse:
The master core must write the data and operations to be performed to memory. Because these must be separate there could be a page fault on write.
After the master core has finished it's work it must load a dirty bit to check if the slave core has finished processing. It could be busy or have been preempted so this could require multiple loads.
The result from the slave core must then be loaded.
You can see how bad that would get given the expense of loads. Lets look at optimizations that can be done if everything is kept on one core:
If some values are known ahead of time they can be factored into 2s and shifts can be done instead. Even better a shift and add potentially performing more operations than 1 at a time.
For 32-bit or smaller numbers the upper and lower bits of a 64-bit processor may be used for addition.
Out of order processing may be done at the CPU's discretion, for example floating point operations are slower than integer operations, so in the situation: 1.2 * 3 * 4 * 5 The CPU will do the 3 * 4 * 5 first and do only 1 floating point operation.
This question already has answers here:
rate ++a,a++,a=a+1 and a+=1 in terms of execution efficiency in C.Assume gcc to be the compiler [duplicate]
(10 answers)
Which is faster? ++, += or x + 1?
(5 answers)
Closed 9 years ago.
I was wondering if the increment and decrement operators ( ++ -- ) have more purpose to it than its plain use to make the code more simple
maybe:
i++;
is more efficient than:
i = i + 1;
?
In many ways, the main purpose of the operators is backwards
compatibility. When C++ was being designed, the general rule
was to do what C did, at least for non-class types; if C hadn't
had ++ and --, I doubt C++ would have them.
Which, of course, begs the question. It's inconceivable that
they would generate different code in a modern compiler, and
it's fairly inconceivable that the committee would introduce
them for optimization reasons (although you never
know—move semantics were introduced mainly for
optimization reasons). But back in the mid-1970s, in the
formative years of C? It was generally believed, at the time,
that they were introduced because they corresponded to machine
instructions on the PDP-11. On the other hand, they were
already present in B. C acquired them from B. And B was an
interpreted language, so there was no issue of them
corresponding to machine instructions. My own suspicion, which
applies to many of the operators (&, rather than and, etc.)
is that they were introduced because development at the time was
largely on teletypes (tty's), and every character you output to
a teletype made a lot of unpleasant noise. So the less
characters you needed, the better.
As to the choice between ++ i;, i += 1; and i = i + 1;:
there is a decided advantage to not having to repeat the i
(which can, of course, be a more or less complex expression), so
you want at least i += 1;. Python stops there, if for no
other reason than it treats assignment as a statement, rather
than as the side effect of an arbitrary expression. With over
30 years of programming in C and C++ under my belt, I still feel
that ++ i is missing when programming in Python, even though I
pretty much restrict myself in C++ to treating assignment as a
statement (and don't embed ++ i in more complicated
expressions).
Performance depends on the type of i.
If it's a built-in type, then optimizers will "notice" that your two statements are the same, and emit the same code for both.
Since you used post-increment (and ignoring your semi-colons), the two expressions have different values even when i is a built-in type. The value of i++ is the old value, the value of i = i + 1 is the new value. So, if you write:
j = i++;
k = (i = i + 1);
then the two are now different, and the same code will not be emitted for both.
Since the post-condition of post-increment is the same as pre-increment, you could well say that the primary purpose of the post-increment operator is that it evaluates to a different value. Regardless of performance, it makes the language more expressive.
If i has class type with overloaded operators then it might not be so simple. In theory the two might not even have the same result, but assuming "sensible" operators i + 1 returns a new instance of the class, which is then move-assigned (in C++11 if the type has a move assignment operator) or copy-assigned (in C++03) to i. There's no guarantee that the optimizer can make this as efficient as what operator++ does, especially if the operator overload definitions are off in another translation unit.
Some types have operator++ but not operator+, for example std::list<T>::iterator. That's not the reason ++ exists, though, since it existed in C and C has no types with ++ but not +. It is a way that C++ has taken advantage of it existing.
The two examples you gave will almost certainly compile to exactly the same machine code. Compilers are very smart. Understand that a compiler rarely executes the code you actually wrote. It will twist it and mould it to improve performance. Any modern compiler will know that i++; and i = i + 1; are identical (for an arithmetic type) and generate the same output.
However, there is a good reason to have both, other than just code readability. Conceptually, incrementing a value many times and adding to a value are different operations - they are only the same here because you are adding 1. An addition, such as x + 3, is a single operation, whereas doing ++++++x represents three individual operations with the same effect. Of course, a smart compiler will also know that for an object of arithmetic type, x, it can do N increments in constant time just by doing x + N.
However, the compiler can't make this assumption if x is of class type with an overloaded operator+ and operator++. These two operators may do entirely different things. In addition, implementing an operator+ as a non-constant time operation would give the wrong impression.
The importance of having both becomes clear when we're dealing with iterators. Only Random Access Iterators support addition and subtraction. For example, a standard raw pointer is a random access iterator because you can do ptr + 5 and get a pointer to the 5th object along. However, all other types of iterators (bidirectional, forward, input) do not support this - you can only increment them (and decrement a bidirectional iterator). To get to the 5th element along with a bidirectional iterator, you need to do ++ five times. That's because an addition represents a constant time operation but many iterators simply cannot traverse in constant time. Forcing multiple increments shows that it's not a constant time operation.
Both would produce same machine instruction(s) in optimized code by a decent compiler.
If the compiler sees i++ is more efficient,then it will convert i=i+1 to i++, or vice-versa. The result will be same no matter what you write.
I prefer ++i . I never write i=i+1.
No, it is simply to make typing simple, and to get simpler looking syntax.
When they are both compiled, they are reduced to the same compiled code, and run at the same speed.
The ++ or -- operator allows it to be combined into other statements rather than i=i+1. For e.g. while (i++ < 10) allows a while loop check and an increment to be done after it. It's not possible to do that with i=i+1.
The ++ or -- operator can be overloaded in other classes to have other meanings or to do increments and decrements with additional actions. Please see this page for more info.
Try to replace ++i or i++ in some more complicated expression. You're going to have difficulties with the preincrement/postincrement feature. You're going to need to split the expression into multiple ones. It's like ternary operator. It is equivalent, the compiler may perform some optimizations regardless on the way you enter the code, but ternary operator and preincrement/postincrement syntax just save you space and readability of the code.
They both are not exactly same , though functionally they are same, there is a difference in precedencei++ has more precedence(more priority) than i=i+1
The difference between i++ and i = i + 1 is that the first expression only evaluates i once and the second evaluates it twice. Consider:
int& f() {
static int value = 0;
std::cout << "f() called\n";
return value;
}
f()++; // writes the message once
f() = f() + 1; // writes the message twice
And if f() returns different references on different calls, the two expressions have vastly different effects. Not that this is good design, of course...
This is more of a philosophical question, but I've seen this a bunch of times in codebases here and there and do not really understand how this programming method came to be.
Suppose you have to set bits 2 and 3 to some value x without changing the other values in the uint. Doing so is pretty trivial and a common task, and I would be inclined to do it this way:
uint8_t someval = 0xFF; //some random previous value
uint8_t x = 0x2; //some random value to assign.
someval = (somval & ~0xC) | (x << 2); //Set the value to 0x2 for bits 2-3
I've seen code that instead or using '|' uses '+':
uint8_t someval = 0xFF; //some random previous value
uint8_t x = 0x2; //some random value to assign.
someval = (somval & ~0xC) + (x << 2); //Set the value to 0x2 for bits 2-3
Are they equivalent?
Yes.
Is one better than the other?
Only if your hardware doesn't have a bitwise OR instruction, but I have never ever ever seen a processor that didn't have a bitwise OR (even small PIC10 processors have an OR instruction).
So why would some programmers be inclined to use '+' instead of '|'? Am I missing some really obvious, uber powerful optimization here?
If you want to perform bitwise operations, use bitwise operators.
If you want to perform arithmetic operations, use arithmetic operators.
It's true that for some values some arithmetic operations can be implemented as simple bitwise operations, but that's essentially an implementation detail to which you should never expose your readers. First and foremost the logic of the code should be clear and if possible self-explanatory. The compiler will choose appropriate low-level operations for you to implement your desire.
That's being philanthropic.
Are they equivalent?
Yes, as long as the bitfield being written to is clear beforehand. Otherwise, they'll go wrong in slightly different ways.
Is one better than the other?
No, although some would say that bitwise operations express the intent more clearly.
So why would some programmers be inclined to use '+' instead of '|'?
Because they're equivalent, and neither is particularly better than the other.
Am I missing some really obvious, uber powerful optimization here?
No.
So why would some programmers be inclined to use '+' instead of '|'?
+ could bring out logical bugs faster. a | a would appear to work, whereas a simple a + a definitely wouldn't (of course, depends on the logic, but the + version is more error-prone).
Of course you should stick to the standard way of doing things (use bitwise operations when you want a bitwise operation, and arithmetic operations when you want to do math).
It's just a question of style. Any modern CPU will complete both operations in the same number of cycles (typically 1). Personally I prefer | in these cases since it more explicitly states to the code reader that you're doing bit twiddling instead of arithmetic.
If you have a bug in your code, then using + could lead to strange behavior, whereas using | would tend to mask the bug. For example, if you accidentally include the same bit twice, ORing it again is a no-op, but adding it will clear the bit and carry up into the next bit (and possibly farther, if more bits are set). So that would usually lead to fail-fast behavior instead of failure-masking behavior, which is generally preferable.
In C++ it's possible to use a logical operator where a biwise operator was intended:
int unmasked = getUnmasked(); //some wide value
int masked = unmasked & 0xFF; // izolate lowest 8 bits
the second statement could be easily mistyped:
int masked = unmasked && 0xFF; //&& used instead of &
This will cause incorrect behaviour - masked will now be either 0 or 1 when it is inteded to be from 0 to 255. And C++ will not ever complain.
Is is possible to design code in such a way that such errors are detected at compiler level?
Ban in your coding standards the direct use of any bitwise operations in an arbitrary part of the code. Make it mandatory to call a function instead.
So instead of:
int masked = unmasked & 0xFF; // izolate lowest 8 bits
You write:
int masked = GetLowestByte(unmasked);
As a bonus, you'll get a code base which doesn't have dozens of error prone bitwise operations spread all over it.
Only in one place (the implementation of GetLowestByte and its sisters) you'll have the actual bitwise operations. Then you can read these lines two or three times to see if you blew it. Even better, you can unit test that part.
This is a bit Captain Obvious, but you could of course apply encapsulation and just hide the bitmask inside a class. Then you can use operator overloading to make sure that the boolean operator&&() as you see fit.
I guess that a decent implementation of such a "safe mask" need not be overly expensive performance-wise, either.
In some instances you might get a compiler warning (I wouldn't expect one in your example though). A tool like lint might be able to spot possible mistakes.
I think the only way to be sure is to define your coding standards to make the difference between the two operators more obvious - something like:
template<typename T>
T BitwiseAnd( T value, T mask ) { return value & mask; }
and ban the bitwise operators & and |
Both operators represent valid operations on integers, so I don't see any way of detecting a problem. How is the compiler supposed to know which operation you really wanted?