I saw a program in C that had code like the following:
static void *arr[1] = {&& varOne,&& varTwo,&& varThree};
varOne: printf("One") ;
varTwo: printf("Two") ;
varThree: printf("Three") ;
I am confused about what the && does because there is nothing to the left of it. Does it evaluate as null by default? Or is this a special case?
Edit:
Added some more information to make the question/code more clear for my question.
Thank you all for the help. This was a case of the gcc specific extension.
It's a gcc-specific extension, a unary && operator that can be applied to a label name, yielding its address as a void* value.
As part of the extension, goto *ptr; is allowed where ptr is an expression of type void*.
It's documented here in the gcc manual.
You can get the address of a label defined in the current function (or
a containing function) with the unary operator &&. The value has
type void *. This value is a constant and can be used wherever a
constant of that type is valid. For example:
void *ptr;
/* ... */
ptr = &&foo;
To use these values, you need to be able to jump to one. This is done
with the computed goto statement, goto *exp;. For example,
goto *ptr;
Any expression of type void * is allowed.
As zwol points out in a comment, gcc uses && rather than the more obvious & because a label and an object with the same name can be visible simultaneously, making &foo potentially ambiguous if & means "address of label". Label names occupy their own namespace (not in the C++ sense), and can appear only in specific contexts: defined by a labeled-statement, as the target of a goto statement, or, for gcc, as the operand of unary &&.
This is a gcc extension, known as "Labels as Values". Link to gcc documentation.
In this extension, && is a unary operator that can be applied to a label. The result is a value of type void *. This value may later be dereferenced in a goto statement to cause execution to jump to that label. Also, pointer arithmetic is permitted on this value.
The label must be in the same function; or in an enclosing function in case the code is also using the gcc extension of "nested functions".
Here is a sample program where the feature is used to implement a state machine:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
void *tab[] = { &&foo, &&bar, &&qux };
// Alternative method
//ptrdiff_t otab[] = { &&foo - &&foo, &&bar - &&foo, &&qux - &&foo };
int i, state = 0;
srand(time(NULL));
for (i = 0; i < 10; ++i)
{
goto *tab[state];
//goto *(&&foo + otab[state]);
foo:
printf("Foo\n");
state = 2;
continue;
bar:
printf("Bar\n");
state = 0;
continue;
qux:
printf("Qux\n");
state = rand() % 3;
continue;
}
}
Compiling and execution:
$ gcc -o x x.c && ./x
Foo
Qux
Foo
Qux
Bar
Foo
Qux
Qux
Bar
Foo
I'm not aware of any operator that works this way in C.
Depending on the context, the ampersand in C can mean many different things.
Address-Of operator
Right before an lvalue, e.g.
int j;
int* ptr = &j;
In the code above, ptr stores the address of j, & in this context is taking the address of any lvalue. The code below, would have made more sense to me if it was written that way.
static int varOne;
static int varTwo;
static int varThree;
static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };
Logical AND
The logical AND operator is more simple, unlike the operator above, it's a binary operator, meaning it requires a left and right operand. The way it works is by evaluating the left and right operand and returning true, iff both are true, or greater than 0 if they are not bool.
bool flag = true;
bool flag2 = false;
if (flag && flag2) {
// Not evaluated
}
flag2 = true;
if (flag && flag2) {
// Evaluated
}
Bitwise AND
Another use of the ampersand in C, is performing a bitwise AND. It's similar as the logical AND operator, except it uses only one ampersand, and performs an AND operation at the bit level.
Let's assume we have a number and that it maps to the binary representation shown below, the AND operation works like so:
0 0 0 0 0 0 1 0
1 0 0 1 0 1 1 0
---------------
0 0 0 0 0 0 1 0
In C++ land, things get more complicated. The ampersand can be placed after a type as to denote a reference type (you can think of it as a less powerful but safe kind of pointer), then things get even more complicated with 1) r-value reference when two ampersands are placed after a type. 2) Universal references when two ampersands are placed after a template type or auto deducted type.
I think your code probably compiles only in your compiler due to an extension of some sorts. I was thinking of this https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C but I doubt that's the case.
Related
Code in case if the image not is visible.
#include <stdio.h>
int fun(int n)
{
if(n=4)
return n;
else
return 2*fun(n+1);
}
int main()
{
printf("%d", fun(2));
}
This is the code snippet and the output is given as 4 by the professor.
How is the output correct?
Is it possible that n=4 is assigned in the 'if-else' statement as the assignment operator is correct, but the "if" condition will not work as the syntax is wrong and the output will be directly given as 4.
The answer is correct, and there aren't any syntax errors.
= is an assignment operator, and in C/C++, (n = 4) is a valid expression that evaluates to true as long as the expression is not (n = 0), because n will then be considered as false by C. Note that in C/C++, 0 is false and everything else is true.
Hence, if (n = 4) is perfectly valid and always evaluates to true. Of course, in the process, there will also be an assignment involved.
Thus, what happens in the code above is that
the integer n is assigned the value 4 in n = 4
(n=4) as an expression returns true.
return n (4).
So the answer is 4.
Assignment in a if-else statement is valid syntax and the branching will depend on the value of n.
Example:
#include <iostream>
int main() {
int n = 2;
if (n = 0) {
std::cout << "Never printed\n";
}
if (n = 4) {
std::cout << "Always printed\n";
}
return 0;
}
Compiler explorer: https://godbolt.org/z/fEYPcq
You should use == operator to make a confront between two compatible values.
if(n = 4) assign 4 to n and then the if statement is always true. So the return value will always be 4.
"Is it possible that n = 4 is assigned in the if-else statement as the assignment operator is correct, but the if condition will not work as the syntax is wrong....?"
The syntax is not wrong and the if condition does work. It is perfectly valid. And yes, the assignment is also valid/correct.
With if (n = 4) you assign the value of 4 to the function-local variable n, although this makes less sense since n is a parameter and is meant to be feed with different values at each call to the function fun().
But I guess the intention of your professor is exactly to demonstrate this trickery, so it makes sense.
So the value of n is not 2 anymore; It is 4.
This is a valid expression for the if condition and evaluates to 1/true since the value/expression to be assigned is or does not evaluate not 0.
Usually a compiler will warn you about doing so nonetheless to avoid any undesired result here by suggesting optional parentheses around the assignment like: if ((n = 4)).
Clang:
warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
GCC:
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
If you explicitly want to remove these warnings, use the -Wno-parentheses flag. But it is recommended not to do so.
Since the if condition is true, it doesn't get to the recursive part in the else condition and the function fun immediately returns n which is 4.
So is the return value of 4 displayed by the call to printf() in the caller.
My favorite to remember that is this:
int war = false;
if (war = true) { launch nuke; }
Credits go to WTP.
Maybe you'll catch the joke. ;-)
Consider a function like the below:
unsigned int fact(unsigned int i) {
if (i <= 1) { return 1; }
return i * fact(i-1);
}
If I were to instantiate a new variable unsigned int f such that f = 0 * fact(5), why does it not "short circuit"?
unsigned int fact(unsigned int i) {
std::cout << "a";
if (i <= 1) { return 1; }
return i * fact(i-1);
}
int main() {
unsigned int f = 0 * fact(5);
}
The output here is aaaaa. If f can only ever be zero, why would it call the function at all, supposing it knew the return type? Does it not evaluate left to right, see 0 * (unsigned int) and know the rvalue will be 0?
Short-circuit evaluation is mandatory for && (logical and), || (logical or) and ? (ternary operator). For the remaining operators it is an (optional) optimization.
The evaluation of fact(5) in the expression 0 * fact(5) can't be in general optimized away just because you know that the outcome of the whole expression is 0 since a call to fact() may introduce side effects (e.g., modify some global variable), so it must be called.
As said in this comment, a good compiler will optimize away the call to fact(5) if it can prove that there are no side effects.
Does it not evaluate left to right, see 0 * (unsigned int) and know the rvalue will be 0?
It could, and it would if the standard told it to.
But it doesn't.
Short-circuiting simply isn't a thing for multiplication. They could have made it a thing, but it would arguably have been confusing.
We're all used to f() || g() potentially skipping the call to g(), but would you really expect 0 * g() to do the same thing? Particularly since 0 is just one out of billions of possible integers? It would be an oddly specific feature. (By contrast true is one out of only two boolean values.)
This isn't about side effects, because the side effects of g() would be skipped by f() || g() if f() returns true. That's just how it is.
In practice, a compiler could elide the call to g() in 0 * g() if it knew that g() had no side-effects (so the program's behaviour wouldn't be changed), but that's not short-circuiting; that's "optimisation".
This question already has answers here:
Setting extra bits in a bool makes it true and false at the same time
(2 answers)
Closed 3 years ago.
Consider the program below.
All comparisons are true with a recent gcc but only the value 1 compares equal with the Visual Studio commandline compiler v. 19.16.27031.1 for x86.
I believe that it's generally OK to write into PODs through char pointers; but is there wording in the standard about writing funny values into bool variables? If it is allowed, is there wording about the behavior in comparisons?
#include <iostream>
using namespace std;
void f()
{
if(sizeof(bool) != 1)
{
cout << "sizeof(bool) != 1\n";
return;
}
bool b;
*(char *)&b = 1;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
*(char *)&b = 2;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
*(char *)&b = 3;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
}
int main()
{
f();
}
P.S. gcc 8.3 uses a test instruction to effectively check for non-zero while gcc 9.1 explicitly compares with 1, making only that comparison true. Perhaps this godbolt link works.
No. This is not OK.
Writting arbitrary data in a bool is much UB (see What is the strict aliasing rule?) and similar to Does the C++ standard allow for an uninitialized bool to crash a program?
*(char *)&b = 2;
This type punning hack invoke UB. According to your compiler implementation for bool and the optimization it is allowed to do, you could have demons flying off your nose.
Consider:
bool b;
b = char{2}; // 1
(char&)b = 2; // 2
*(char*)&b = 2; // 3
Here, lines 2 and 3 have the same meaning, but 1 has a different meaning. In line 1, since the value being assigned to the bool object is nonzero, the result is guaranteed to be true. However, in lines 2 and 3, the object representation of the bool object is being written to directly.
It is indeed legal to write to an object of any non-const type through an lvalue of type char, but:
In C++17, the standard does not specify the representation of bool objects. The bool type may have padding bits, and may even be larger than char. Thus, any attempt to write directly to a bool value in this way may yield an invalid (or "trap") object representation, which means that subsequently reading that value will yield undefined behaviour. Implementations may (but are not required by the standard to) define the representation of bool objects.
In C++20, my understanding is that thanks to P1236R1, there are no longer any trap representations, but the representation of bool is still not completely specified. The bool object may still be larger than char, so if you write to only the first byte of it, it can still contain an indeterminate value, yielding UB when accessed. If bool is 1 byte (which is likely), then the result is unspecified---it must yield some valid value of the underlying type (which will most likely be char or its signed or unsigned cousin) but the mapping of such values to true and false remains unspecified.
Writing any integer values into a bool through a pointer to a type other than bool is undefined behavior, because those may not match the compiler's representation of the type. And yes, writing something other than 0 or 1 will absolutely break things: compilers often rely on the exact internal representation of boolean true.
But bool b = 3 is fine, and just sets b to true (the rule for converting from integer types to bool is, any nonzero value becomes true and zero becomes false).
It's OK to assign values other than true and false to a variable of type bool.
The RHS is converted to a bool by using the standard conversion sequence to true/false before the value is assigned.
However, what you are trying to do is not OK.
*(char *)&b = 2; // Not OK
*(char *)&b = 3; // Not OK
Even assigning 1 and 0 by using that mechanism is not OK.
*(char *)&b = 1; // Not OK
*(char *)&b = 0; // Not OK
The following statements are OK.
b = 2; // OK
b = 3; // OK
Update, in response to OP's comment.
From the standard/basic.types#basic.fundamental-6:
Values of type bool are either true or false.
The standard does not mandate that true be represented as 1 and/or false be represented as 0. An implementation can choose a representation that best suits their needs.
The standard goes on to say this about value of bool types:
Using a bool value in ways described by this International Standard as “undefined,” such as by examining the value of an uninitialized automatic object, might cause it to behave as if it is neither true nor false.
Storing the value char(1) or char(0) in its memory location indirectly does not guarantee that the values will be properly converted to true/false. Since theose value may not represent either true or false in an implementation, accessing those values would lead to undefined behavior.
In general, it's perfectly find to assign values other than 0 or 1 to a bool:
7.3.14 Boolean conversions
[conv.bool]
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer-to-member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.
But your casting is another question entirely.
Be careful thinking it's ok to write to types through pointers to something else. You can get very surprising results, and the optimizer is allowed to assume certain such things are not done. I don't know all the rules for it, but the optimizer doesn't always follow writes through pointers to different types (it is allowed to do all sorts of things in the presence of undefined behavior!) But beware, code like this:
bool f()
{
bool a = true;
bool b = true;
*reinterpret_cast<char*>(&a) = 1;
*reinterpret_cast<char*>(&b) = 2;
return a == b;
}
Live: https://godbolt.org/z/hJnuSi
With optimizations:
g++: -> true (but the value is actually 2)
clang: -> false
main() {
std::cout << f() << "\n"; // g++ prints 2!!!
}
Though f() returns a bool, g++ actually prints out 2 in main here. Probably not expected.
I am interrested wheather standard says anything about possible values of bool type type after casting it to integer type.
For example following code:
#include <iostream>
using namespace std;
int main() {
bool someValue=false;
*((int*)(&someValue)) = 50;
cout << someValue << endl;
return 0;
}
prints 1 even though it's forced to store value 50. Does standard specify anything about it? Or is compiler generating some method for type bool as:
operator int(){
return myValue !=0 ? 1 : 0;
}
Also why is casting like following:
reinterpret_cast<int>(someValue) = 50;
forbidden with error
error: invalid cast from type 'bool' to type 'int'
(For all above I user GCC 5.1 compiler.)
The way you are using it exhibits UB, because you write outside of the bool variable's boundaries AND you break strict aliasing rule.
However, if you have a bool and want to use it as a an int (this usually happens when you want to index into an array based on some condition), the standard mandates that a true bool converts into 1 and false bool converts into 0, no matter what (UB obviously excluded).
For example, this is guaranteed to output 52 as long as should_add == true.
int main(){
int arr[] = {0, 10};
bool should_add = 123;
int result = 42 + arr[should_add];
std::cout << result << '\n';
}
This line *((int*)(&someValue)) = 50; is at least non standard. The implementation could use a lesser rank for bool (say 1 or 2 bytes) that for int (say 4 bytes). In that case, you would write past the variable possibly erasing an other variable.
And anyway, as you were said in comment, thanks to the strict aliasing rule almost any access through a casted pointer can be seen as Undefined Behaviour by a compiler. The only almost legal one (for the strict aliasing rule) would be:
*((char *) &someValue) = 50;
on a little endian system, and
*(((char *) &someValue) + sizeof(bool) - 1) = 50;
on a big endian one (byte access has still not be forbidden).
Anyway, as the representation of bool is not specified by the standard directly writing something in a bool can lead to true or false depending on implementation. For example an implementation could considere only the lowest level bit (true if val&1 is 1, else 0), another one could considere all bits (true for any non 0 value, false for only 0). The only thing that standard says is that a conversion of a 0 leads to false and of a non 0 leads to true.
But was is mandated by standard is the conversion from bool to int:
4.5 Integral promotions [conv.prom]
...A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true
becoming one.
So this fully explains that displaying a bool can only give 0 or 1 - even if as the previous operation invoked UB, anything could have happen here including this display
You invoked Undefined Behaviour - shame on you
This question already has answers here:
Can I assume (bool)true == (int)1 for any C++ compiler?
(5 answers)
Closed 8 years ago.
Consider the code
bool f() { return 42; }
if (f() == 1)
printf("hello");
Does C (C99+ with stdbool.h) and C++ standards guarantee that "hello" will printed? Does
bool a = x;
is always equivalent to
bool a = x ? 1 : 0;
Yes. You are missing a step though. "0" is false and every other int is true, but f() always returns true ("1"). It doesn't return 42, the casting occurs in "return 42;".
In C macro bool (we are speaking about the macro defined in stdbool.h) expands to _Bool that has only two values 0 and 1.
In C++ the value of f() in expression f() == 1 is implicitly converted to int 1 according to the integral promotion.
So in my opinion this code
bool f() { return 42; }
if (f() == 1)
printf("hello");
is safe.
In C++, bool is a built-in type. Conversions from any type to bool always yield false (0) or true (1).
Prior to the 1999 ISO C standard, C did not have a built-in Boolean type. It was (and still is) common for programmers to define their own Boolean types, for example:
typedef int BOOL;
#define FALSE 0
#define TRUE 1
or
typedef enum { false, true } bool;
Any such type is at least 1 byte in size, and can store values other than 0 or 1, so equality comparisons to 0 or 1 are potentially unsafe.
C99 added a built-in type _Bool, with conversion semantics similar to those for bool in C++; it can also be referred to as bool if you have #include <stdbool.h>.
In either C or C++, code whose behavior is undefined can potentially store a value other than 0 or 1 in a bool object. For example, this:
bool b;
*(char*)&b = 2;
will (probably) store the value 2 in b, but a C++ compiler may assume that its value is either 0 or 1; a comparison like b == 0 or b == true may either succeed or fail.
My advice:
Don't write code that stores strange values in bool objects.
Don't compare bool values for equality or inequality to 0, 1, false, or true.
In your example:
bool f() { return 42; }
Assuming this is either C++ or C with <stdbool.h>, this function will return true or, equivalently, 1, since the conversion of 42 to bool yields 1.
if (f() == 1)
printf("hello");
Since you haven't constructed any strange bool values, this is well behaved and will print "hello".
But there's no point in making the comparison explicitly. f() is already of type bool, so it's already usable as a condition. You can (and probably should) just write:
if (f())
printf("hello");
Writing f() == 1 is no more helpful than writing (f() == 1) == 1).
In a real program, presumably you'll have given your function a meaningful name that makes it clear that its value represents a condition:
if (greeting_required())
printf("hello");
The only real trick that I know of, that is useful with pre-C99 environments is the double negation
int a = 42;
if ( (!!a) != 0 ) printf("Hello\n");
this will print Hello because the result of the !! operation is a boolean that is true when the value is non-zero, false otherwise. But this is gonna cost you 2 negation to get the boolean that you want, in modern standards this is redundant because you will get the same result without the !! and it's a result granted by the language.