I have the following code:
#define MIN(a,b) (a <= b ? a : b)
void main()
{
int a = 5;
int* p = &a;
int result = MIN(*p++,12);
printf("%i",result);
}
Theoretically the output should be something smaller than 12, but it turned out giving 34 as its result. So I'm wondering is there something wrong with that inline function or the pointer?
BTW, I meant to have *p++ there rather than (*p)++. I understand it's gonna increment the address and unbox it.
So another question is normally what could be the value of the next address? In this case, what is the value of *p++?
This line:
int result = MIN(*p++,12);
expands to:
int result = (*p++ <= 12 ? *p++ : 12);
^^^^ ^^^^
So p gets incremented twice, and the value returned is garbage (note that this is actually undefined behaviour).
And this is why the use of such macros is strongly discouraged - you really don't want nasty side-effects like this.
Use a proper inline function instead of a macro:
inline int MIN(int a, int b)
{
return a <= b ? a : b;
}
Related
If I do something like this:
int a = 1;
int b = 2;
a = a + b;
a gives 3 in this instance, however if I do something like this:
int a = 1;
int b = 2;
int a = a + b
a gives a very large number (1827585825)
Can anyone explain why this occurs?
Redefinition of variable as you attempted is not allowed in C, and fails to compile. However, a slightly modified version of your code does compile:
int main() {
int a = 1;
int b = 2;
{
int a = a + b;
// use a
}
return 0;
}
int a = a + b is valid, but doesn't mean what you think it does. The a in a + b refers to the inner and as-yet uninitialized variable a, and not to the outer a. Using it in an expression is undefined behavior and results in garbage output.
Your code is invalid and it will not compile at all.
The second a definition has to be in a different scope like in the example below.
#include <stdio.h>
int a = 1;
int b = 2;
int main(void)
{
int a = a + b; //declares new a variable which has undetermined value
}
The second definition of a hides the global one and newly defined int variable will not be initialized. You take this not initialized variable (having undetermined value) and add another value to it. The result will also undetermined. It is Undefined Behaviour.
https://www.tutorialspoint.com/cprogramming/c_scope_rules.htm
I really wonder why output is: 12 instead of 9 in following code:
#include <stdio.h>
int a = 4, b = 2;
int c = 3;
int f(void);
int main(void) {
printf("%3d\n", f());
printf("%3d%3d%3d\n", a, b, c);
return 0;
}
int f(void) {
int b, c;
a = b = c = 4;
return (a + b + c);
}
I mean since b and c local variables initialized as in the f function when function returned they no longer exist so they shouldn't be returned. Can anybody explain?
int k(void) {
int d = 5;
return d;
}
Like the k function returns nothing, right?
You made function f return summation of "values" of a, b and c, not variables themselves. By declaring variables named by b and c in function f, global variable b and c are shadowed by local variables, so any changes (like assigning 4 like you did) doesn't affect global variables with same names.
You seem to be under the impression, that f is not returning a single value but the entire expression a + b + c and that expression is evaluated in the calling function. That is not what happens.
Inside the function f, the global a is set to 4 as is the locals b and c. The values of each of those are added together resulting in the value 12, and that value is what is returned from the function.
Expressions are evaluated at the point they occur.
I have a struct of the form:
struct foo {
bool has_value;
int value;
}
I want to create a macro, which can be used to assign value as follows:
ASSIGN(foo) = 0;
or
ASSIGN(foo) += 5;
when the macro is:
#define ASSIGN(s) \
s->has_value = true; s->value
However, the macro is not if safe. In the example below if will "eat" the first part of the ASSIGN macro.
if (cond)
ASSIGN(foo) += 5;
Any proposal on how to make ASSIGN if safe?
Use a comma operator, and throw in parens for good measure.
#define ASSIGN(s) \
((s)->has_value = true), (s)->value
In an if-statement it would expand to:
if (cond)
((foo)->has_value = true), (foo)->value += 5;
However, macros in this usage are a very bad idea.
You can almost always come up with abusive code that will break your macro.
Even if it works, it will confuse future programmers who may read your code.
Here is one bad way this macro will break:
ASSIGN(foo) = M_PI;
printf("Sin of PI/2 = %f\n", sin(ASSIGN(foo) *= 0.5));
You might expect that to print 1.
It probably won't even compile.
Any proposal on how to make ASSIGN if safe?
You cannot, in general, do this. You should not use macros for an lvalue. It's a terrible idea, and it will most probably lead to crazy and impossible to find bugs.
This really seems like an XY problem. In your case, as I understand, you want to create a macro to simplify an expression that should be done over and over multiple times in your code.
Instead of using a simple one-argument macro, you can define a macro with two arguments. This way, it will be more compatible with the rest of your code, while still achieving the same result, using a more consistent semantic, which is also "if-safe".
Here it is (I'm calling it ASSIGN_FOO just to distinguish it from yours):
#define ASSIGN_FOO(x, v) do { (x)->has_value = true; (x)->value = v; } while (0)
struct foo var;
ASSIGN_FOO(var, 123);
If you're wondering about that do { ... } while (0), have a look here.
In case you want the macro to return the assigned value though (like you would expect from a normal assignment), this is not a good option.
Instead of using a macro, you can define an inline function, declaring it with __attribute__ ((always_inline)). This way, the compiler integrates the function's code directly into the caller, and the function will act exactly as a macro when the program is compiled, except that it is now more powerful as it can be used in more contexts.
inline int __attribute__ ((always_inline)) assign_foo(struct foo *x, int value) {
x->has_value = true;
x->value = value;
return x->value;
}
struct foo var;
assign_foo(var, 123);
In addition to this, it doesn't make much sense to use the macro you defined when updating the value in your struct, as it can easily lead to unwanted undefined behavior, like the following:
struct foo var;
ASSIGN(var) += 5;
Which expands to:
var->has_value = true; var->value += 5; // Undefined behavior, var->value used uninitialized!
The solution here is:
If you already know that the value is present, it doesn't make sense to re-assign has_value = true, you can just do the increment directly:
var->value += 10;
If you don't know if the value is present, use a function to do it safely instead:
inline int __attribute__ ((always_inline)) increment_foo(struct foo *x, int value) {
if (!x->has_value) {
x->has_value = true;
x->value = value;
} else {
x->value += value;
}
return x->value;
}
increment_foo(var, 10);
Comparison:
struct foo x;
printf("%d\n", ASSIGN(x) = 3); // Compilation error.
printf("%d\n", ASSIGN_FOO(x, 3); // Compilation error.
printf("%d\n", assign_foo(x, 3)); // No problem.
struct foo y;
printf("%d\n", ASSIGN(y) += 3); // Compilation error.
ASSIGN(y) += 3; printf("%d\n", y->value); // Undefined behavior.
printf("%d\n", increment_foo(y, 3)); // No problem.
Such syntax-breaking macros are usually a bad idea but you can do it with
#define ASSIGN(s) ((s).has_value=1,&(s))->value
if you want it to take an lvalue or
#define ASSIGN(sp) ((sp)->has_value=1,(sp))->value
if you want it to take a pointer.
Working example (https://godbolt.org/z/fHAGRa):
#include <stdbool.h>
#include <stdio.h>
struct foo {
bool has_value;
int value;
};
#define ASSIGN(s) ((s).has_value=1,&(s))->value
int main()
{
struct foo x;
ASSIGN(x) = 21;
printf("%d\n", ASSIGN(x) *= 2 ); //prints 42
return ASSIGN(x); //returns the last value (42)
}
It doesn't protect from double-evaluation—for that you'd need the expression statement extension or a helper inline function such as
static inline struct foo *set_has_value_return_ptr(struct foo *X){
return X->has_value=1, X;
}
#define ASSIGN(s) (set_has_value_return_ptr(&(s)))->value
Explanation:
The naive ((s).has_value=1,(s).value) or ((s).has_value=1,(s)).value wouldn't work because of lvalue to rvalue conversion done by the comma operator, but ((s).has_value=1,&(s))->value or (*((s).has_value=1,&(s))).value will because pointer dereferencing (*) and -> always yield lvalues regardless of whether their pointer argument was an lvalue or an rvalue.
I just found somewhere a code like :
#include"stdio.h"
typedef struct st
{
int num;
char c;
int abc;
} Str, *pStr;
#define MyStr(Dcn) Str(Dcn)
int main()
{
Str Str1;
MyStr(Dcn);
return 0;
}
Please tell what the #define line means here? As it is not giving any compilation problem. So if I use #define something to a "structure with parentheses" then what happens?
Here Dcn can be anything not with quotes. When I used a number instead it showed compilation error.
This defines an alias for Str. It is equivalent to
int main()
{
Str Str1;
Str(Dcn);
return 0;
}
Which simply declares a variable Dcn of type Str.
It's a function-like macro, it's expanded to the right-hand side with the arguments replaced.
A classical example is this, to compute max of two values:
#define MAX(a, b) ((a) > (b) ? a : b)
You can use it like this:
int hello = 12, there = 47;
int what = MAX(hello, there);
The second line will expand to:
int what = ((12) > (47) ? 12 : 47);
In other words, what will be 47. Note that this macro evaluates its arguments more than once, which can be harmful if there are side-effects.
As of C99, you can also do variadic preprocessor macros.
The code you're showing will expand to:
Str Str1;
Str(Dcn); /* This is the macro-expansion. */
Since b++ is post-increment,what happens to the increment of b if used as return b++ as in the following program?
#include<stdio.h>
int foo(int);
int main()
{
int a=8;
printf("%d",foo(a));
}
int foo(int a)
{
static int b=a*a;
return b++;
}
Edit
#include<stdio.h>
int foo();
int main()
{
foo();
foo();
}
int foo()
{
static int b=1;
printf("%d\n",b);
return b++;
}
Result
1
2
As I saw in my edit, why is b incremented at all?Isn't return supposed to exit that function immediately?Why is b incremented even after control returns to main()?Aren't all activities in the function supposed to end after return?
Many C (sub-)expression have a value and a side effect.
The value of b++ is the value of b before evaluating the expression; its side effect is to increase the value in b by one.
So, the expression return b++; returns the previous value of b and updates b.
When b is static the update stays around for the next function call;
when b is a plain old local variable, the update is lost (a smart compiler will even not emit code to update the object).
Actually, this code doesn't compile, because b's initializer isn't a constant.
Since b is static, it's essentially a global variable, and it gets initialized before main, at which point a doesn't exist.
If on the other hand we compile this as C++, b is initialized the first time that foo is called - so gets the value 64. At the return, b++ is incremented and stored as 65 - but the return value is 64. So if you call foo again, it will return 65 (and b is 66).
Edit based on edited code:
So, the code essentially performs:
int temp = b;
b = b + 1;
return temp;
This is the way that C is define. The result of x++ is the previous value x, but the value of x is increment. Since static is essentially a global (but without a name, so you can't use it outside of that function), the value persists between calls to the function, and it is initialized before main is called.
return b++; is equivalent to:
int c = b; b = c + 1; return c;
To answer your new questions:
- The function exits after return indeed, but before it returns, the expression b++ must be evaluated first. Evaluating such an expression will result in b being incremented.
- All activities in the function "end" after return but b is declared as a static variable, in which case its value persists through subsequent executions of the function.
To make it easier for you to understand, a post increment is like the following function
int postincrement(int& x) {
int y = x;
x = x + 1;
return y;
}
(Of course the compiler could optimize a b++ if it finds that incrementing b has no effect at all, but in this case it does have an effect (increment the static int b) so it can't be optimized out.)
This post-increment is completely useless - because b has local scope, its incremented value is disposed after return. If your compiler is smart, it most likely to optimize it out.