Can anyone please explain how this works
#define maxMacro(a,b) ( (a) > (b) ) ? (a) : (b)
inline int maxInline(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int i = 1; j = 2, k = 0;
k = maxMacro(i,j++); // now i = 1, j = 4 and k = 3, Why ?? Where is it incremented ?
//reset values
i = 1; j = 2, k = 0;
k = maxInline(i,j++); // now i = 1, j = 3, and k = 2, Why ??
return 0;
}
So, I want to know where exactly is the value of j incremented, while checking
condition or while returning or while calling ?
a. using macro
b. using inline method
UPDATE :
Thanks to all, now I understand this. But just out of curiosity, why would anyone do j++ while calling method, why not increment j after calling method, this way it would be less confusing. I saw this piece of code somewhere so asking it !!
The issue is the preprocessor does just straight text substitution for macros.
maxMacro(i, j++)
becomes
( (i) > (j++) ) ? (i) : (j++)
As you can see, it does two increments when j is greater.
This is exactly why you should prefer inline functions over macros.
k = maxMacro(i,j++);
expands to:
k = ( (i) > (j++) ) ? (i) : (j++)
Because of the sequence point of ?: the behaviour of this is well defined. When i is less than the initial value of j, j is incremented twice and k receives the once incremented value of j.
(If i were greater than the initial value of j, then j would be incremented only once when evaluating (i) > (j++), k would be assigned that value of (i) and the second increment would not be performed.)
In:
k = maxInline(i,j++);
maxInline is called with the values i and j before increment (1 and 2), j is incremented before the function call, and k is assigned the return value of maxInline (2).
Macro results in textual expansion. It happens before the compiler is even considering expressions and operators, and immediately after it had split the input text into individual tokens. Thus, the following line:
k = maxMacro(i,j++);
is exactly equivalent to the following line after macro expansion:
k = ( (i) > (j++) ) ? (i) : (j++);
Obviously, there are two increments here.
On the other hand, inline functions are just functions, and work exactly like non-inline ones for the purpose of the call. And in function calls, expressions in the argument list are evaluated first, and then their values are bound to respective parameter names inside the function body. Thus, the evaluation only happens once.
This is why macro is evil!
A macro is literal text subsitution by the proprocessor before your compiler gets to it so k = maxMacro(i,j++); becomes ( (i) > (j++) ) ? (i) : (j++);. I hope you see the problem here.
In the (inline) function call, the value of a and b is passed by value into the function where the initial value of i and j is passed in, after which j increment.
Calling a macro is not the same as calling a function.
The preprocessor replaces the reference to maxMacro(i,j++)
with literal text that looks like this.
(i) > (j++) ? (i) : (j++)
A post increment operator uses the current value of its target,
and then increments its target. So if i = 1 and j = 2, the following
happens:
(i) > (j++) // 1 is compared to 2, and j is incremented to 3
? (i) : (j++) 2 is greater than 1, so the "b" value is passed
along. j++ is invoked again, so the previous value 3 is returned
from the expression, but as a side effect, j is incremented to 4.
On the other hand, the inline function works just like a non
inline function as far as how the parameter variables are treated.
j++ is referenced once when it is put on the
stack as part of the function call. The function call operates
with a b value of 2 and returns its result(2) while j is incremented
to 3 as a side effect.
Note: your question indicates k=3 after the call to maxInline. I got
k=2 after that call - the result I'd expect.
I hope this clarifies things . . .
K
Check out the CERT C Coding standard:
PRE00-C. Prefer inline or static functions to function-like macros
This is a great resource, lots of information about various little gotchas that one should avoid to make their code clean, stable, and secure :)
Weird. So far nobody has mentioned that the inline function option is type-safe, where the macro isn't!
Related
I really do not have any clue about how to solve this task, can someone please help?
Consider the following function definition:
void f(int i, int &j) {
j = i+1;
i = j*2;
j += i;
}
In the following code:
int x = 4, y = 7;
f(x, y);
What are the final values of x and y?
For starters you could just run the code... but otherwise we can try and predict the output.
For starters the function f has two parameters, i and j. The & Infront of the j means that the value of the function input is passed by reference (the value of the variable will be edited).
So now let's evaluate the function with inputs 4, 7. We get:
j = 4+1 = 5
i = 10
j += i, j = 15
Because the variable y was passed by reference, its value will become 15. The variable x was passed by value, so it doesn't get affected and thus stays as 4.
Simply just run the code.Anyway the output will be
x=4(because it is passed as pass by value ->any change will not affect the outside the function f)
y=15(because it is passed as pass by reference->any change will affect the outside the function f)
char i;
for (i = 1; i < 10, i++;)
{
cout << (i+1) << endl;
}
return 0;
I understand that for loop has the following syntax:
for(initialization; condition; increment)
{
}
As I run the debug, why it never checks the condition and it eventually stops at i = 0?
(Thank you Damien and Andars, I don't know why the "on purpose" statement was removed, but you interpret my question correctly. Could someone explain why the complier skips the condition before the comma, and why the loop stop at i = 0 instead of looping forever? Thanks!)
I believe he is indicating that he wrote the code that way on purpose.
To answer, i++ will always return true. The last value is the value that matters with comma separated statements, so the loop will not stop.
Edit for elaborations:
It isn't simply using a logical or, it disregards what is before the comma and only takes the last value. The value of anything non-zero is considered true, and since i starts at 1, and goes up, it will always be non-zero (until it overflows and wraps back around, which explains why i ends at 0).
If you say:
x = 4, 5, 6;
x will be equal to 6, the last value.
Change
for (i = 1; i < 10, i++;)
to
for (i = 1; i < 10; i++)
Change to
for (i = 1; i < 10; i++) //Notice correct placement of ;
It seems to me also that the code was written incorrectly on purpose. As others have mentioned, the comma operator will discard the value of the i<10 and only i++ will be evaluated as condition. This will return true until i overflows (values only from -127 to 127) and ends up at -1, when i++ will return 0 and the loop exits. Thus the final value for i will be 0.
Because you used the comma operator instead of a semi-colon
I´m studing the code of OpenCV, and I came across the next few lines:
The function´s var are:
CvMat* _err;
CvMat* _mask;
int i, count = _err->rows*_err->cols, goodCount = 0;
for( i = 0; i < count; i++ )
goodCount += mask[i] = err[i] <= threshold; // This line is strange for me
return goodCount;
What does the line I indicated actually do? Because, call me strange, I have never seen anything like that.
For your information:
Yes, the code is working :D
The code is part of the CvModelEstimator2::findInliers function.
That line is evil.
Nevertheless, it assigns 1 to mask[i] if err[i] <= threshold and 0 otherwise.
Then it increments goodCount if the condition holds.
mask[i] = (err[i] <= threshold);
goodCount += mask[i];
So you're confused about this line:
goodCount += mask[i] = err[i] <= threshold;
You can use a C operator precedence table to figure out the order of operations here, but it's fairly unambiguous anyway:
Compare err[i] against threshold. This results in a bool (true or false).
Assign the result to mask[i]. I think the bool will be converted to a number here, which will be 1 for true or 0 for false.
Use the new value of mask[i] (which is the result of the = operator) to increment goodCount (basically, goodCount will end up containing the count of "true" values found in step 1).
To me the most subtle part of that line is the fact that assignment returns a reference to the left-hand side (i.e. the target). This is sometimes seen in a less complex expression like this:
if ((mem = malloc(42)) == NULL)
throw ...
goodCount += mask[i] = err[i] <= threshold;
Mixing assignment and comparison in the same statement is generally a bad idea.
The recommended approach is to (1) know what is the precedence of the involved operators, and (2) split the statement into several ones, to enhance readability.
I have the following c++ code snippet. I have a basic understanding of c++ code.Please correct my explanation of the following code where ever necessary:
for (p = q->prnmsk, s = savedx->msk, j = sizeof(q->prnmsk);
j && !(*p & *s); j--, p++, s++);
What does it contain: q is char *q(as declared) is type of structure MSK as per code.
q->prnmsk contains byte data where prnmask containd 15 bytes.
It is similar for s.
So in the for loop as j decreases it will go through each byte and perform this !(*p & *s) operation to continue the loop and eventually if the condition is not met the loop will exit else j will run till j==0.
Am I correct? What does *p and *s mean? Will it contain the byte value?
Some (like me) might think that following is more readable
int j;
for (j = 0; j < sizeof(q->prnmsk); ++j)
{
if ((q->prnmsk[j] & savedx->msk[j]) != 0) break;
}
which would mean that q->prnmsk and savedx->msk are iterated to find the first occurence of where bit-anding both is not zero. if j equals sizeof(q->prnmsk), all bit-andings were zero.
Yes, you are right. !(*p & *s) means that they want to check if q->prnmsk and savedx->msk don't have corresponding bits set to 1 simultaneously.
I've noticed on a number of occasions when refactoring various pieces of C and C++ code that a comma is used rather than a semi-colon to seperate statements. Something like this;
int a = 0, b = 0;
a = 5, b = 5;
Where I would have expected
int a = 0, b = 0;
a = 5; b = 5;
I know that C and C++ allow use of commas to seperate statements (notably loop headers), but what is the difference if any between these two pieces of code? My guess is that the comma has been left in as the result of cut & pasting, but is it a bug and does it effect execution?
It doesn't make a difference in the code you posted. In general, the comma separates expressions just like a semicolon, however, if you take the whole as an expression, then the comma operator means that the expression evaluates to the last argument.
Here's an example:
b = (3, 5);
Will evaluate 3, then 5 and assign the latter to b. So b = 5. Note that the brackets are important here:
b = 3, 5;
Will evaluate b = 3, then 5 and the result of the whole expression is 5, nevertheless b == 3.
The comma operator is especially helpful in for-loops when your iterator code is not a simple i++, but you need to do multiple commands. In that case a semicolon doesn't work well with the for-loop syntax.
The comma is a operator that returns a value which is always the 2nd (right) argument while a semicolon just ends statements. That allows the comma operator to be used inside other statements or to concatenate multiple statements to appear as one.
Here the function f(x) gets called and then x > y is evaluated for the if statement.
if( y = f(x), x > y )
An example when it's used just to avoid a the need for block
if( ... )
x = 2, y = 3;
if( ... ) {
x = 2;
y = 3;
}
The comma operator evaluates all operands from left to right, and the result is the value of the last operand.
It is mostly useful in for-loops if you want to do multiple actions in the "increment" part, e.g (reversing a string)
for (int lower = 0, upper = s.size() - 1; lower < upper; ++lower, --upper)
std::swap(s[lower], s[upper]);
Another example, where it might be an option (finding all occurrences in a string):
#include <string>
#include <iostream>
int main()
{
std::string s("abracadabra");
size_t search_position = 0;
size_t position = 0;
while (position = s.find('a', search_position), position != std::string::npos) {
std::cout << position << '\n';
search_position = position + 1;
}
}
In particular, logical and cannot be used for this condition, since both zero and non-zero can mean that the character was found in the string. With comma, on the other hand, position = s.find() is called each time when the condition is evaluated, but the result of this part of the condition is just ignored.
Naturally there are other ways to write the loop:
while ((position = s.find('a', search_position)) != std::string::npos)
or just
while (true) {
position = s.find('a', search_position);
if (position == std::string::npos)
break;
...
}
As Frank mentioned, how the comma operator is used in your example doesn't cause a bug. The comma operator can be confusing for several reasons:
it's not seen too often because it's only necessary in some special situations
there are several other syntactic uses of the comma that may look like a comma operator - but they aren't (the commas used to separate function parameters/arguments, the commas used to separate variable declarations or initializers)
Since it's confusing and often unnecessary, the comma operator should be avoided except for some very specific situations:
it can be useful to perform multiple operation in one or more of a for statement's controlling expressions
it can be used in preprocessor macros to evaluate more than one expression in a single statement. This is usually done to allow a macros to do more than one thing and still be a a single expression so the macro will 'fit' in places that only allow an expression.
The comma operator is a hackish operator pretty much by definition - it's to hack in 2 things where only one is allowed. It's almost always ugly, but sometimes that's all you've got. And that's the only time you should use it - if you have another option, don't use the comma operator.
Off the top of my head I can't think of too many other reasons to use the operator, since you can get a similar effect by evaluating the expressions in separate statements in most other situations (though I'm sure that someone will comment on a another use that I've overlooked).
One usage would be in code golfing:
if (x == 1) y = 2, z = 3;
if (x == 1) { y = 2; z = 3; }
The first line is shorter, but that looks too confusing to use in regular development.