Local variable definied in an if statement hehaves unexpectedly - c++

Originally I wanted to pack a bunch of statement into a single line so my stuff can be used as a simple macro inside an if.
I needed to do 3 things:
Create a local variable
Update that with a function
Check if the updated variable matches something else
Here's my quick draft code:
#include <iostream>
#include <stdint.h>
#define MAGIC_VALUE 42
bool MyMockedFunction(uint64_t* outElement)
{
*outElement = MAGIC_VALUE;
return true;
}
static const uint64_t global_should_match_this = MAGIC_VALUE;
int main()
{
// Originally I wanted to declare the variable in one single line (as a defined macro, which should be used in an IF statement)
// That's why I have so many things packed into the same line
// It may or may not (latter is more probable) a good idea, but that's not the question here
if (uint64_t generatedElement = 123456 && MyMockedFunction(&generatedElement) && global_should_match_this == generatedElement)
{
// I would expect generatedElement == MAGIC_VALUE
printf("Inside value: %llu\n", generatedElement);
}
else
{
printf("Unmatched\n");
}
return 0;
}
I understand that programatically it may not be foolproof and it's prone to misuse if I put it in a macro (also macros are evil), but in my case it would be a very controlled environment, just to make my code easier to read.
So, the question is here - why the generatedElement equals to 1 after running? Is it an undefined behaviour in any way?
I've checked in a compiler disassembler that it's 1 because in the end the comparison's value (is the expression true? yes -> 1 -> that's what is moved into the variable. But it looks unreasonable to me. Why would a compiler do so? :O Checked both on MSVC & GCC, both produces the same output.

Your condition is really:
uint64_t generatedElement = (123456 && MyMockedFunction(&generatedElement) && global_should_match_this == generatedElement)
Which means you initialize generatedElement with the boolean result. And also lead to undefined behavior as you use the uninitialized (and indeterminate) value of generatedElement.
If your compiler support if statements with initializer (new in C++17) then you can do
if (uint64_t generatedElement = 123456; MyMockedFunction(&generatedElement) && global_should_match_this == generatedElement)
{
// ...
}
Otherwise you have to split up into separate variable definition and condition:
uint64_t generatedElement = 123456;
if (MyMockedFunction(&generatedElement) && global_should_match_this == generatedElement)
{
// ...
}

Related

Why is the following code illegal in C++ [duplicate]

This question already has answers here:
Declaring and initializing a variable in a Conditional or Control statement in C++
(9 answers)
Closed 7 years ago.
I want to create an if where a variable is declared, assigned and checked. If the variable's value is acceptable, I want to use it inside if body. Here's an example of how I thought I could do that:
if ((int result = Foo()) != 0) {
// use result
}
I assumed that Foo() returns some value, which is assigned to result, and returned by assignment operator =, and finally checked against 0 in != 0. Unfortunately, it results in a compilation error:
main.cpp:31:10: error: expected primary-expression before ‘int’
if ((int i = Foo()) != 0)
^
main.cpp:31:10: error: expected ‘)’ before ‘int’
Why is this error happening? And what ways could there be to fix it?
The logic is supported, but declaring a variable within an if statement and using it this way is not. The reason is related to the fact that an initializer works differently than a regular assignment, but working around this is easy and trivial.
Just do something like this instead.
int result;
if ((result = Foo()) != 0) {
// use result
}
Your reasoning seems to be based on the assumption that = in
if ((int result = Foo()) != 0)
is an assignment operator and that int result = Foo() is "just an expression" that evaluates to something.
This is not true.
The int result = Foo() part is not an expression in C++. It is a declaration with an initializer. The = in initializer syntax is not an assignment operator at all. It is just a syntactic element that coincidentally uses the same character as assignment operator. The int result = Foo() is not an expression and it does not "evaluate" to any result.
Because if the above, support for something like
if (int result = Foo())
requires special treatment, which severely limits the flexibility of this syntax. What you tried in your code goes outside the bounds of what's allowed by that special treatment.
Bjarne uses this construct as a scope restrictor in 6.3.2.1 The C++ programming language as a recommendation.
Use:
if (int result = Foo()) {
// use non-zero result
}
It is particularly useful with pointers
if (Foo* result = GetFoo()) {
// use valid Foo
}
The !=0 part is redundant as truthiness is !=0.
The extended construct with the comparison is not allowed.
Further discussion of this construct from here
It fails because it's illegal. It's also ugly. #Jonathan Wood suggested declaring the variable outside the if. I suggest calling Foo outside, too:
int result = Foo();
if(result!=0) ...
The (x=f())!=y construct, while legal as an if condition, only makes sense in a loop, where
`while((c=getchar())!='\n)
... do something with c ...
Is the shorter and nicer equivalent of
c = getchar();
while(c!='\n')
{
...
c = getchar(c);
}
It saves writing the call to getchar() twice. It saves nothing when used in an if, so there's no point in using it.
Try this:
if ( int i = (Foo() != 0) ? Foo() : 0 ){
cout << "Hello. Number i = " << i;
}

How to declare a variable in the brackets of if statement?

I want to declare a local variable in the brackets of an if statement.
For example.
if((char c = getc(stdin)) == 0x01)//This is not OK with g++.
{
ungetc(c, stdin);
}
What I want is, to see if the character is the one I want.
To say it commonly, I want to use the variable(char c) both in the line of if and the body of if, but not outside the if.
But g++(GCC 4.8.1) says expected primary-expression before 'char'.
I wonder if there's a way to do that, because I don't want something like
char c = getc(stdin);
if(c == 0x01)
{
bla...
}
If it's the namespace pollution you are worrying about you can always define the if statement within a block:
{
char c = getc(stdin);
if(c == 0x01)
{
// ...
}
}
So that c will only last until the end of the block is reached.
I didn't know how to create a variable and test its value with an if until after seeing some of the posted solutions. However, you could use switch. This would allow you to react to additional values (perhaps EOF):
switch (int c = getc(stdin)) {
case 0x01: ungetc(c, stdin); break;
case EOF: // ...handle EOF
default: break;
}
You could always place the if statement in an inlined function instead, and the code will look a little cleaner. If you really want the source code right at that location, but without creating a new scope around an if with a new variable, then perhaps a lambda would be acceptable to you.
[](int c){ if (c == 0x01) ungetc(c, stdin); }(getc(stdin));
Since you are only comparing against one valuem your particular problem does not require a variable at all, so you can simply do:
if (getc(stdin) == 0x01) {
char c = 0x01;
ungetc(c, stdin); //or bla...
}
If you are wanting to compare against a set of values, then the switch suggestion is the better option.
Jerry Coffin's solution looks appealing, but it really boils down to:
if (int c = (getc(stdin) == 0x01)) //...
This is probably not what you really wanted, as it does not generalize well if you want to compare to a value different from 0x01.
Potatoswatter's solution seems closer to what you want, but perhaps it would be nicer to pull the type out into a standalone class:
template <typename T>
class SetAndTest {
const T test_;
T set_;
public:
SetAndTest (T s = T(), T t = T()) : set_(s), test_(t) {}
operator bool () { return set_ == test_; }
operator bool () const { return set_ == test_; }
operator T & () { return set_; }
operator T () const { return set_; }
};
//...
if (auto c = SetAndTest<int>(getc(stdin), 0x01)) {
ungetc(c, stdin); //or bla...
}
You can define the variable inside the if statement just fine. For example, this should compile:
if (int ch = getchar())
;
The problem is that the type (e.g., int) must follow immediately after the opening parenthesis. The extra parenthesis you have is what's causing compilation to fail. So, if you really want to do this, you'll need to get a little clever and use something like this:
if (char ch = 0 || ((ch = getchar()) == 0x1))
This lets you get the creation and initialization of ch done, then after that part of the expression is complete, put in the parentheses around the ch=getchar() to override the precedence of assignment vs. comparison.
Note that && and || do short-circuit evaluation, so you need to be careful with your initialization. You can use either:
if (char ch = 0 || ...
...or:
if (char ch = 1 && ...
...but if you try to use if (ch = 1 || ... or if (ch = 0 && ..., the short-circuit evaluation will keep the right operand (the part you really care about) from being evaluated at all.
Now the caveat: while I'm reasonably certain this code fits the standard's requirements, and most (all?) current compilers will accept it, it's likely to cause most programmers reading the code some serious head-scratching figuring out what you've done, and why. I'd be extremely hesitant (at best) about using this "technique" in real code.
Edit: It's been pointed out that the result from this may be even more misleading than some initially expect, so I'll try to clarify the situation. What happens is that a value is read from input. That value is assigned to ch and compared to 0x1. So far so good. After that, the result of the comparison (converted to an integer, so either 0 or 1) will be assigned to ch. I believe it has sufficient sequence points that the result is defined behavior. But it's probably not what you, or anybody, want -- thus the advice that you probably don't want to use this, and the mention that it would probably leave most programmers scratching their heads, wondering what you were trying to do. In the very specific case of comparing to 0x1, the value of ch inside the if statement will be 1, but it's more or less a coincidence. If you were comparing to 0x2, the value of ch inside the if would still be 1, not 2.

Using the comma operator in if statements

I tried the following:
if(int i=6+4==10)
cout << "works!" << i;
if(int i=6+4,i==10)
cout << "doesn't even compile" << i;
The first works fine while the second doesn't compile. Why is this?
EDIT: Now I know that the first one may not work as I intend it to. The value of i inside the if scope will be 1, not 10. (as pointed out by one of the comments on this question).
So is there a way to initialize and use a variable inside of an if statement at the same time similar to for(int i=0;i<10;i++)? So that you could produce something like if((int i=6+4)==10) (which will not compile) where the value of I inside the if scope would be 10?
I know you could declare and initialize I before the if statement but is there a way to do this within the statement itself?
To give you an idea why I think this would be usefull.
if(int v1=someObject1.getValue(), int v2=someObject2.getValue(), v1!=v2)
{
//v1 and v2 are visible in this scope
//and can be used for further calculation without the need to call
//someObject1.getValue() und someObject2.getValue() again.
}
//if v1==v2 there is nothing to be done which is why v1 und v2
//only need to be visible in the scope of the if.
The expression used as an initializer expression must be an assignment-expression so if you want to use a comma operator you must parenthesize the initializer.
E.g. (not that what you are attempting makes much sense as 6 + 4 has no side effects and the value is discarded and i == 10 uses the uninitialized value of i in its own initializer.)
if (int i = (6 + 4, i == 10)) // behaviour is undefined
Did you really mean something like this?
int i = 6 + 4;
if (i == 10)
When using the form of if that declares a new variable the condition checked is always the value of the initialized variable converted to bool. If you want the condition to be an expression involving the new variable you must declare the variable before the if statement and use the expression that you want to test as the condition.
E.g.
int i;
if ((i = 6 + 4) == 10)
I doubt seriously either example works to do anything useful. All that it does is evaluate to "true" in a complicated fashions.
But the reason the second one doesn't compile is that it's interpreted as two declarations: int i = 6+4; int i==10 and int i==10 isn't valid because that's an equality operator, not an assignment.
There are different alternatives, because what you want cannot be done (you cannot mix the comma operator with declarations). You could, for example, declare the variable outside of the if condition:
int i = 6+4;
if ( i == 10 ) ...
Or you can change the value of i to be 0 instead of 10 and recalculate i inside the else block:
if ( int i = (6+4)-10 ) ; else {
i += 10;
// ...
}
Much simpler, don't declare the variable at all, since you know the value inside the loop:
if ( (6+4)==10 ) {
int i = 10;
// ...
}
Unless of course you need the value of i in the case where it is not 10, in which case the second option is the most appropriate.
As of C++17 what you were trying to do is finally possible:
if (int i=6+4; i==10)
cout << "works, and i is " << i << endl;
Note the use of ; of instead of , to separate the declaration and the actual condition.

retval = false && someFunction(); // Does someFunction() get called?

I'm currently working with the Diab 4.4 C++ compiler. It's a total POS, non ANSI-compliant, and I've found problems with it in the past.
I'm wondering if the following problem is an issue with the compiler, or a shortcoming in my knowledge of C++
I realize that the form of x = x && y; will short-circuit the y part if x is false. What the compiler is doing is short-circuiting in the case of x = x && y(); where y() is a non-const function.
class A
{
int _a;
A(int a) { _a = a; }
bool someFunction() { _a = 0; return true; }
};
main(...)
{
A obj = A(1);
bool retval = false;
retval = retval && A.someFunction();
/* What is the value of A._a here? */
}
What seems wrong to me is the fact that the compiler is doing this short-circuiting even though someFunction() is not a const function. If it's not const, is the compiler overstepping its bounds by skipping A.someFunction() when retval is false?
Also, I realize this issue can be avoided by writing retval = A.someFunction() && retval; but I'd really like to know why this is happening.
Short circuiting applies to all expressions, regardless of const-ness. Skipping the call to someFunction() is correct.
The && and || operators are defined to evaluate lazily, this is the way the language works. If you want the side effects to always happen, invoke the function first and stash the result, or refactor the function to split the work from the state query.
As others have explained, || and && always perform short-circuit evaluation.
Also note that short-circuit evaluation can be very useful, since it lets you write code like this:
retval = obj_pointer && obj_pointer->SomeBooleanMethod();
Without short-circuit evaluation, this would crash on a NULL pointer.
It doesn't matter if the second operand to && is const or not. After the first operand evaluates to false the return value is known, so there's no reason to evaluate the second operand.
If the function has side effects that require it to be executed, put it first.
Short-circuit evaluation has nothing to do with const or non-const. It happens no matter what.
The statement A() && B(); will do exactly what if (A()) B(); does (although it isn't a perfect substitute, as the second one allows an else). This is sometimes used to change a statement into an expression (such as when writing a macro, or embedding it in another statement).
The && operator is also called the shortcut operator, which means it only evaluates the second part if the first part returned true. That's the main difference between && and &:
value = func1() && func2(); // evaluates func2() only if func1() returns true
value = func1() & func2(); // evaluates both func1() and func2()
For && operator,
1 && X = X
0 && X = 0
so in case first var is 0, compiler will evaluate the expression to 0, no question, what ever the X is.
Compiler will ignore the X part as it wont impact the result. Here X can be any thing function/variable/expression.....

static initialization in c

I have a function which is passed a list of ints, until one value is "-1" and calculates the minimum.
If the function gets called couple times, it is supposed to return the minimum between all calls.
So I wrote something like that:
int min_call(int num, ...)
{
va_list argptr;
int number;
va_start(argptr, num);
//static int min = va_arg(argptr, int); //////// the questioned line
static int all_min = -1;
int min = va_arg(argptr, int);
if (min != -1)
{
while ((number = va_arg(argptr, int)) != -1)
{
if (number < min)
{
min = number;
}
}
}
if (min < all_min || all_min == -1)
{
all_min = min;
}
return all_min;
}
I want to know something about the marked line... why can't I call it - the compiler says because the expression being used to initialize the static int is not constant.
For some reason I remember that I can initialize a static variable and know that the initializing statement will be called only once (the first time) it's written in C++.
If that line would be available it would have saved me couple variables.
Is there a difference between C and C++ in this matter?
Yes, C++ allows for statics to be lazily initialized at runtime. Effectively C++ turn static initialization into this:
static int XX_first_time = 1;
if (XX_first_time)
{
// run the initializer
XX_first_time = 0;
}
While this is convenient, it is not thread safe. The standard does not require this to be thread safe although some compilers have done that anyway (gcc 4.x does thread safe initialization unless explicitly requested not to with -fno-threadsafe-statics).
C requires statics be to have their value configured at compile time. Yes, this is more limited but is more in line with C doing little work for you behind your back (C can be thought of as portable assembly).
C static initialization must be done with constant values, i.e. something that is known at compile-time. Because your call to va_arg() won't resolve until runtime, you can't use it as a static initializer. You could assign a known-bad value to min at initialization and then simply call va_arg() after the variable has been initialized (John Dibling's example code does exactly that).
Also, it's important to note that static initialization only happens once per scope (in this case, your function), so even if your commented-out line worked, it would only be executed once and not each time the function is invoked (as I think you were expecting).
As others have said, in C, static variables must be initialized with compile-time constants. If you omit the initial value, it is taken as 0.
Now, about the logic in your function. I think the function is written much more clearly like this (I am not changing the form of the function):
#include <limits.h>
int min_call(int num, ...)
{
va_list argptr;
int number;
static int min = INT_MAX;
va_start(argptr, num);
while ((number = va_arg(argptr, int)) != -1)
if (number < min)
min = number;
va_end(argptr);
return min;
}
If num should also be included in the calculation of the minimum, then you will need an additional check along the lines of if (num < min) min = num;.
I also have trouble understanding if (min < all_min || all_min == -1 ) line. Since all_min was initialized to -1 in the beginning and then never touched, the if condition will always be true.
Note that the initialization of min is to INT_MAX and not INT_MIN as one of the comments says, and that we must call va_end().
You can't do what you're trying to do because the static is intialized before the program starts running -- argptr doesn't exist in context yet. You could try something like this:
va_start( argptr, num );
static bool init = 0;
static int min = -1;
if( !init )
{
min = va_arg( argptr, int );
init = true;
}
static int all_min = -1;
Static doesn't just mean it only gets set the first time you call it. It means that it's set at compile time. The compiler doesn't know how to call your va_arg function at compile time. (It doesn't make any sense until you're in run-time and running the program and passing it arguments.)
(edit - In C. Someone else has noted C++ is different.)
This doesn't exactly answer your question, but the other answers have done a good job of doing so already.
However, I think you are approaching this very simple problem from the wrong direction. If you want your functions to be portable and re-usable, you should try to minimize their side effects.
For example, instead of keeping state data in your function (evil), you should be keeping that data in a variable (or struct) local to the scope that is using it. Like this:
{
int min_so_far;
min_so_far = min_call(NULL, 4, 7, 2, -6, 3, -12);
min_so_far = min_call(&min_so_far, -11, 5, 3, 8, -3);
printf("%d\n", min_so_far); //should output -12
}
The first argument to min_call would be an int*, and if it was passed in as NULL, then the function would disregard it. Otherwise, each argument would be compared against the int that was passed in.
This isn't as convenient, but it's definitely safer, and you will be able to use this function in more than one place in the application. Thinking about the reusability of your code is a good habit to get into.