volatile argument to a function? - c

This question has a comment by #ideasman42 that says:
Not sure its worth another question, but interested to know why you
might write void func(int volatile arg);
I thought it was worth a question, but didn't see one, so here it is. What, if any, is the effect of doing that?
What sparked it for me, was writing a slightly different set of wrapper functions than what the Raspberry Pi Pico SDK provides. Specifically:
io_rw_32 _i2s_get_hw_clkdiv(struct _i2s* i2s)
{
return i2s->pio_ch->sm[i2s->pio_sm].clkdiv;
}
void _i2s_set_hw_clkdiv(struct _i2s* i2s, io_rw_32 clkdiv)
{
i2s->pio_ch->sm[i2s->pio_sm].clkdiv = clkdiv;
}
A header file buried deep in the SDK says typedef volatile uint32_t io_rw_32;.
Sure, I could do
uint32_t _i2s_get_hw_clkdiv(struct _i2s* i2s)
{
return i2s->pio_ch->sm[i2s->pio_sm].clkdiv;
}
void _i2s_set_hw_clkdiv(struct _i2s* i2s, uint32_t clkdiv)
{
i2s->pio_ch->sm[i2s->pio_sm].clkdiv = clkdiv;
}
instead, and (probably?) generate the exact same code, but if for some unforeseen reason that typedef changes, I'd rather have as few datatype conversions as possible.

What, if any, is the effect of doing that?
It tells the compiler the value of the parameter must be reloaded each time it is used (or, if the source code modifies the parameter, the new value must be written each time).
There is almost never a reason to do that. With const, it can be useful to declare a function parameter as const if you intend never to modify it. If you declare it const and modify it due to a typo where you intended some other name, the compiler will warn you. However, volatile is normally used for accessing special hardware, but function parameters are managed by the compiler and should not need volatile. One time when you might want to use volatile with a function parameter is when you are debugging and want to be able to change the parameter from the debugger. Then using volatile will ensure the generated code gets the new value each time it is used in the source code. Since this would only be for debugging, it should not be used in deployed code.
… generate the exact same code…
No, it does not. With a plain uint32_t parameter, Clang, with optimization enabled, does not reload the parameter from memory when it is used multiple times. When preparing for the second function call in this code:
void foo0(uint32_t clkdiv)
{
bar(clkdiv);
bar(clkdiv);
}
Clang copies the value of clkdiv from a register where it has cached it. In contrast, in this code:
void foo1(io_rw_32 clkdiv)
{
bar(clkdiv);
bar(clkdiv);
}
Clang reloads the parameter from memory. Interestingly, it is not memory where the parameter was passed to the function but rather is memory in the stack frame of the called function. The argument was passed to the function in a register, and the function stored it in memory to create the parameter. (A parameter is an object that is initialized with the value of an argument; it is not the argument itself.)
It is a mistake for the code to be using a volatile type as a parameter, as it results in inefficient code generation.

Related

C: Using static volatile with "getter" function and interruptions

Suppose I have the following C code:
/* clock.c */
#include "clock.h"
static volatile uint32_t clock_ticks;
uint32_t get_clock_ticks(void)
{
return clock_ticks;
}
void clock_tick(void)
{
clock_ticks++;
}
Now I am calling clock_tick (i.e.: incrementing clock_ticks variable) within an interruption, while calling get_clock_ticks() from the main() function (i.e.: outside the interruption).
My understanding is that clock_ticks should be declared as volatile as otherwise the compiler could optimize its access and make main() think the value has not changed (while it actually changed from the interruption).
I wonder if using the get_clock_ticks(void) function there, instead of accessing the variable directly form main() (i.e.: not declaring it as static) can actually force the compiler to load the variable from memory even if it was not declared as volatile.
I wonder this as someone told me this could be happening. Is it true? Under which conditions? Should I always use volatile anyway no matters if I use a "getter" function?
A getter function doesn't help in any way here over using volatile.
Assume the compiler sees you've just fetched the value two lines above and not changed it since then.
If it's a good optimizing compiler, I would expect it to see the function call has no side effect simply optimize out the function call.
If get_clock_ticks() would be external (i.e. in a separate module), matters are different (maybe that's what you remember).
Something that can change its value outside normal program flow (e.g. in an ISR), should always be declared volatile.
Don't forget that even if you currently compile the code declaring get_clock_ticks and the code using it as separate modules, perhaps one day you will use link-time or cross-module optimisation. Keep the "volatile" even though you are using a getter function - it will do no harm to the code generation in this case, and makes the code correct.
One thing you have not mentioned is the bit size of the processor. If it is not capable of reading a 32-bit value in a single operation, then your get_clock_ticks() will sometimes fail as the reads are not atomic.

How do I find variables that should be constants in C?

So, I've got this code:
uint8_t* pbytes = pkt->iov[0].iov_base;
that creates a pointer to the start of an ethernet packet in a structure.
And I ask my friend to look at the code, and he says: "You're not modifying that, and it would be really confusing if you did, so make it const".
And this seems like a good idea, so:
const uint8_t* pbytes = pkt->iov[0].iov_base;
or even:
const uint8_t * const pbytes = pkt->iov[0].iov_base;
And now I am thinking, I bet there are loads of other places where I could have done that, and I bet the compiler is going to be better at finding them than me.
Any ideas how I ask it the question? (gcc preferred, but no problems using a different compiler or a linting tool as long as they will run on unix).
GCC has a flag to suggest beneficial attributes like const
-Wsuggest-attribute=[pure|const|noreturn|format] Warn for cases where adding an attribute may be beneficial. The attributes currently
supported are listed below.
-Wsuggest-attribute=pure
-Wsuggest-attribute=const
-Wsuggest-attribute=noreturn
Warn about functions that might be candidates for attributes pure, const or noreturn. The compiler only
warns for functions visible in other compilation units or (in the case
of pure and const) if it cannot prove that the function returns
normally. A function returns normally if it doesn’t contain an
infinite loop or return abnormally by throwing, calling abort or
trapping. This analysis requires option -fipa-pure-const, which is
enabled by default at -O and higher. Higher optimization levels
improve the accuracy of the analysis.
Src: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
const propagates. In fact it often becomes a problem and is called "const poisoning". The issue is a function like strchr() which could be called with a const pointer or with a variable one. But if it returns a const *, the string cannot be modified through the pointer, which is often what you want to do.
But if you just make your constant data const at the point immediately after you read it in / initialise it, the compiler will star throwing errors at you every time you try to pass to a non-const qualified context.

Usage of the const keyword

I know that using the const keyword on function arguments provides better performance, but I always forget to add it. Is the compiler (GCC in this case) smart enough to notice that the variabele never changes during the function, and compile it as if I would have added const explicitly?
You have a common misunderstanding about const. Only making an object const means that its value never changes, and then it's not just during a function, it never changes.
Making a parameter to a function const does not mean its value never changes, it just means that function cannot change the value through that const pointer. The value can change other ways.
For example, look at this function:
void f(const int* x, int* y)
{
cout << "x = " << *x << endl;
*y = 5;
cout << "x = " << *x << endl;
}
Notice that it takes a const pointer to x. However, what if you call it like this:
int x = 10;
f(&x, &x);
Now, f has a const pointer, but it's to a non-const object. So the value can change, and it does since y is a non-const pointer to the same object. All of this is perfectly legal code. There's no funny business here.
So there's really no answer to your question since it's based entirely on false premises.
Is the compiler (GCC in this case) smart enough to notice that the
variabele never changes during the function, and compile it as if I
would have added const explicitly?
Not necessarily. For example:
void some_function(int *ptr); // defined in another translation unit
int foo(int a) {
some_function(&a);
return a + 1;
}
The compiler can't see what some_function does, so it can't assume that it won't modify a.
Link-time optimization could perhaps see what some_function really does and act accordingly, but as far as this answer is concerned I'll consider only optimization for which the definition of some_function is unavailable.
int bar(const int a) {
some_function((int*)&a);
return a + 1;
}
The compiler can't see what some_function does, but it can assume that the value of a does not change anyway. Therefore it can make any optimizations that apply: maybe it can keep a in a callee-saves register across the call to some_function; maybe it computes the return value before making the call instead of after, and zaps a. The program has undefined behavior if some_function modifies a, and so from the compiler's POV once that happens it doesn't matter whether it uses the "right" or "wrong" value for a.
So, by in this example by marking a const you have told the compiler something that it cannot otherwise know -- that some_function will not modify *ptr. Or anyway that if it does modify it, then you don't care what your program's behavior is.
int baz(int a) {
some_function(NULL);
return a + 1;
}
Here the compiler can see all relevant code as far as the standard is concerned. It doesn't know what some_function does, but it does know that it doesn't have any standard means to access a. So it should make no difference whether a is marked const or not because the compiler knows it doesn't change anyway.
Debugger support can complicate this situation, of course -- I don't know how things stand with gcc and gdb, but in theory at least if the compiler wants to support you breaking in with the debugger and modifying a manually then it might not treat it as unmodifiable. The same applies to the possibility that some_function uses platform-specific functionality to walk up the stack and mess with a. Platforms don't have to provide such functionality, but if they do then it conflicts with optimization.
I've seen an old version of gcc (3.x, can't remember x) that failed to make certain optimizations where I failed to make a local int variable const, but in my case gcc 4 did make the optimization. Anyway, the case I'm thinking of wasn't a parameter, it was an automatic variable initialized with a constant value.
There's nothing special about a being a parameter in any of what I've said -- it could just as well be any automatic variable defined in the function. Mind you, the only way to for a parameter to get the effect of initialization with a constant value is to call the function with a constant value, and for the compiler to observe the value for that call. This tends to happen only when the function is inlined. So inlined calls to functions can have additional optimizations applied to them that the "out-of-line" function body isn't eligible for.
const, much like inline, is only a hint for a compiler and does not guarantee any performance gains. The more important task of const is to protect programmers from themselves so they do not unwilling modify variables where they shouldn’t be modified.
1) Really const is not affecting your performance directly. It may in some cases make simpler points-to analysis (so prefer const char* to char*), but const is more about semantics and readability of your code.
2) CV-qualified type forms different type in C and C++. So your compiler, even if it sees profit from making default const, will not do it, because it will change type and may lead to surprisingly odd things.
As part of the optimization the compiler is taking a deep look at when memory locations are read or written. So the compiler is quite good at detecting when a variable is not changed (const) and when it is changed. The optimizer does not need you to tell him when a variable is const.
Nevertheless you should always use const when appropriate. Why? Because it makes interfaces more clear and easier to understand. And it helps detect bugs when you are changing a variable that you did not want to change.

C function parameter optimization: (MyStruct const * const myStruct) vs. (MyStruct const myStruct)

Example available at ideone.com:
int passByConstPointerConst(MyStruct const * const myStruct)
int passByValueConst (MyStruct const myStruct)
Would you expect a compiler to optimize the two functions above such that neither one would actually copy the contents of the passed MyStruct?
I do understand that many optimization questions are specific to individual compilers and optimization settings, but I can't be designing for a single compiler. Instead, I would like to have a general expectation as to whether or not I need to be passing pointers to avoid copying. It just seems like using const and allowing the compiler to handle the optimization (after I configure it) should be a better choice and would result in more legible and less error prone code.
In the case of the example at ideone.com, the compiler clearly is still copying the data to a new location.
In the first case (passing a const pointer to const) no copying occurs.
In the second case, copying does occur and I would not expect that to be optimized out if for no other reason because the address of the object is taken and then passed through an ellipsis into a function and from the point of view of the compiler, who knows what the function does with that pointer?
More generally speaking, I don't think changing call-by-value into call-by-reference is something compilers do. If you want copy by reference, implement it yourself.
Is it theoretically possible that a compiler could detect that it could just convert the function to be pass-by-reference? Yes; nothing in the C standard says it cannot..
Why are you worrying about this? If you are concerned about performance, has profiling shown copy-by-value to be a significant bottleneck in your software?
This topic is addressed by the comp.lang.c FAQ:
http://c-faq.com/struct/passret.html
When large structures are passed by value, this is commonly optimized by actually passing the address of the object rather than a copy. The callee then determines whether a copy needs to be made, or whether it can simply work with the original object.
The const qualifier on the parameter makes no difference. It is not part of the type; it is simply ignored. That is to say, these two function declarations are equivalent:
int foo(int);
int foo(const int);
It's possible for the declaration to omit the const, but for the definition to have it and vice versa. The optimization of the call cannot hinge on this const in the declaration. That const is not what creates the semantics that the object is passed by value and hence the original cannot be modified.
The optimization has to preserve the semantics; it has to look as if a copy of the object was really passed.
There are two ways you can tell that a copy was not passed: one is that a modification to the apparent copy affects the original. The other way is to compare addresses. For instance:
int compare(struct foo *ptr, struct foo copy);
Inside compare we can take the address of copy and see whether it is equal to ptr. If the optimization takes place even though we have done this, then it reveals itself to us.
The second declaration is actually a direct request by the user to receive a copy of the passed struct.
const modifier eliminates the possibility of any modifications made to the local copy, however, it is does not eliminate all the reasons for copying.
Firstly, the copy has to maintain its address identity, meaning that inside the second function the &myStruct expression should produce a value different from the address of any other MyStruct object. A smart compiler can, of course, detect the situations that depend on the address identity of the object.
Secondly, aliasing presents another problem. Imagine that the program has a global pointer MyStruct *global_struct and inside the second function someone modifies the *global_struct. There's a possibility that the *global_struct is the same struct object that was passed to the function as an argument. If no copy was made, the modifications made to *global_struct will be visible through the local parameter, which is a disaster. Aliasing issues are much more difficult (and in general case impossible) to resolve at compilation time, which is why compilers usually won't be able to optimize out the copying.
So, I would expect any compiler to perform the copying, as requested.

Function pointer cast to different signature

I use a structure of function pointers to implement an interface for different backends. The signatures are very different, but the return values are almost all void, void * or int.
struct my_interface {
void (*func_a)(int i);
void *(*func_b)(const char *bla);
...
int (*func_z)(char foo);
};
But it is not required that a backends supports functions for every interface function. So I have two possibilities, first option is to check before every call if the pointer is unequal NULL. I don't like that very much, because of the readability and because I fear the performance impacts (I haven't measured it, however). The other option is to have a dummy function, for the rare cases an interface function doesn't exist.
Therefore I'd need a dummy function for every signature, I wonder if it is possible to have only one for the different return values. And cast it to the given signature.
#include <stdio.h>
int nothing(void) {return 0;}
typedef int (*cb_t)(int);
int main(void)
{
cb_t func;
int i;
func = (cb_t) nothing;
i = func(1);
printf("%d\n", i);
return 0;
}
I tested this code with gcc and it works. But is it sane? Or can it corrupt the stack or can it cause other problems?
EDIT: Thanks to all the answers, I learned now much about calling conventions, after a bit of further reading. And have now a much better understanding of what happens under the hood.
By the C specification, casting a function pointer results in undefined behavior. In fact, for a while, GCC 4.3 prereleases would return NULL whenever you casted a function pointer, perfectly valid by the spec, but they backed out that change before release because it broke lots of programs.
Assuming GCC continues doing what it does now, it will work fine with the default x86 calling convention (and most calling conventions on most architectures), but I wouldn't depend on it. Testing the function pointer against NULL at every callsite isn't much more expensive than a function call. If you really want, you may write a macro:
#define CALL_MAYBE(func, args...) do {if (func) (func)(## args);} while (0)
Or you could have a different dummy function for every signature, but I can understand that you'd like to avoid that.
Edit
Charles Bailey called me out on this, so I went and looked up the details (instead of relying on my holey memory). The C specification says
766 A pointer to a function of one type may be converted to a pointer to a function of another type and back again;
767 the result shall compare equal to the original pointer.
768 If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.
and GCC 4.2 prereleases (this was settled way before 4.3) was following these rules: the cast of a function pointer did not result in NULL, as I wrote, but attempting to call a function through a incompatible type, i.e.
func = (cb_t)nothing;
func(1);
from your example, would result in an abort. They changed back to the 4.1 behavior (allow but warn), partly because this change broke OpenSSL, but OpenSSL has been fixed in the meantime, and this is undefined behavior which the compiler is free to change at any time.
OpenSSL was only casting functions pointers to other function types taking and returning the same number of values of the same exact sizes, and this (assuming you're not dealing with floating-point) happens to be safe across all the platforms and calling conventions I know of. However, anything else is potentially unsafe.
I suspect you will get an undefined behaviour.
You can assign (with the proper cast) a pointer to function to another pointer to function with a different signature, but when you call it weird things may happen.
Your nothing() function takes no arguments, to the compiler this may mean that he can optimize the usage of the stack as there will be no arguments there. But here you call it with an argument, that is an unexpected situation and it may crash.
I can't find the proper point in the standard but I remember it says that you can cast function pointers but when you call the resulting function you have to do with the right prototype otherwise the behaviour is undefined.
As a side note, you should not compare a function pointer with a data pointer (like NULL) as thee pointers may belong to separate address spaces. There's an appendix in the C99 standard that allows this specific case but I don't think it's widely implemented. That said, on architecture where there is only one address space casting a function pointer to a data pointer or comparing it with NULL, will usually work.
You do run the risk of causing stack corruption. Having said that, if you declare the functions with extern "C" linkage (and/or __cdecl depending on your compiler), you may be able to get away with this. It would be similar then to the way a function such as printf() can take a variable number of arguments at the caller's discretion.
Whether this works or not in your current situation may also depend on the exact compiler options you are using. If you're using MSVC, then debug vs. release compile options may make a big difference.
It should be fine. Since the caller is responsible for cleaning up the stack after a call, it shouldn't leave anything extra on the stack. The callee (nothing() in this case) is ok since it wont try to use any parameters on the stack.
EDIT: this does assume cdecl calling conventions, which is usually the default for C.
As long as you can guarantee that you're making a call using a method that has the caller balance the stack rather than the callee (__cdecl). If you don't have a calling convention specified the global convention could be set to something else. (__stdcall or __fastcall) Both of which could lead to stack corruption.
This won't work unless you use implementation-specific/platform-specific stuff to force the correct calling convention. For some calling conventions the called function is responsible for cleaning up the stack, so they must know what's been pushed on.
I'd go for the check for NULL then call - I can't imagine it would have any impact on performance.
Computers can check for NULL about as fast as anything they do.
Casting a function pointer to NULL is explicitly not supported by the C standard. You're at the mercy of the compiler writer. It works OK on a lot of compilers.
It is one of the great annoyances of C that there is no equivalent of NULL or void* for function pointers.
If you really want your code to be bulletproof, you can declare your own nulls, but you need one for each function type. For example,
void void_int_NULL(int n) { (void)n; abort(); }
and then you can test
if (my_thing->func_a != void_int_NULL) my_thing->func_a(99);
Ugly, innit?

Resources