I have written a C program and I'm compiling with GCC (for an arm MCU).
I have a function that changes the address of void pointer to point to another void,and so on.
The problem is that the Linker/Compiler think that the code is unused and discard it.
I have tried attribute(( used )) but that didn't work.
The voids and code are in separate .h/.c file from the main.h/c but are included in the main.c
Code:
void q2_h(void (*ptr)(uint8_t), uint8_t a) {
if (a == 3) {
ptr = (void*) q3_h;
} else {
ptr = (void*) q22_h;
}
}
Definition:
void q2_h(void (*ptr)(uint8_t), uint8_t a)__attribute__((used));
Input Pointer:
void (*ptr)(void*,uint8_t);
which is not completely right because the (uint8_t) is missing but I'm not sure about the syntax.
So if if you have any idea on how to sol
Problems:
The code changes a local variable, not the function pointer in the calling code. So it is not "seemingly dead", it's truly dead. Instead of fiddling around with attributes, listen to what your compiler is trying to tell you.
Always use typedef when dealing with function pointers, it would have made the bug more obvious.
You cannot cast a function pointer to a void pointer or vice versa. void* is only a generic pointer type for object pointers. You shouldn't need to cast at all, or your code is attempting fishy invalid pointer conversions, which would be a bug.
Corrected code might look something like:
typedef void func_t (uint8_t);
void q2_h(func_t** ptr, uint8_t a) {
if (a == 3) {
*ptr = q3_h;
} else {
*ptr = q22_h;
}
}
Related
I am trying to have an array of arrays of function pointers, but cannot assign to it, only statically initialize it:
#define N_INPUTS 2
#define N_STATES 2
void one()
{
//do stuff
}
void two()
{
//do stuff
}
//etc.
typedef void (*action_map[N_INPUTS])();
action_map my_action_maps[N_STATES];
//this would work:
//action_map am1 = {one, two};
//action_map am2 = {two, one};
//action_map my_action_maps[N_STATES] = { am1, am2 };
void init()
{
action_map am1;
am1[0] = one;
am1[1] = two;
my_action_maps[0] = am1; //error "expression must be a modifiable lvalue"
//however this works:
my_action_maps[0][0] = one;
my_action_maps[0][1] = two;
}
//the idea is to then handle input depending on a state with
//my_action_maps[state][input]();
I am not sure why is this happening, my_action_maps is just an array of pointers to function pointers, isn't it? Why it can initialized with initializer but then it is not modifiable?
This isn't really about function pointers, they are just making it harder to see the issue.
The type action_map is an array of function pointers. am1 and my_action_maps[0] are both of that type. But in C, you cannot assign an array to another array. It's the same issue as this:
int a[3] = {1,2,3};
int b[3] = {4,5,6};
a = b; // error
Current versions of gcc and clang both give a more useful message that explicitly says the problem is assigning to an array type. You might consider switching or upgrading your compiler.
You need to copy the elements one by one with a loop, or with memcpy. Thanks to array-pointer decay, you could do:
memcpy(my_action_maps[0], am1, sizeof(action_map));
Alternatively, you could wrap your action_map type in a struct, since you can assign structs to one another. But then it's a little more awkward to access the members.
typedef struct {
void (*actions[2])();
} action_map;
action_map my_action_maps[2];
void init(void) {
action_map am1;
am1.actions[0] = one;
am1.actions[1] = two;
// or: action_map am1 = { { one, two } };
// or: action_map am1 = { one, two };
my_action_maps[0] = am1; // ok
}
By the way, regarding your function and type declarations using empty parentheses, I suggest reading func() vs func(void) in C99 and Is it better to use C void arguments "void foo(void)" or not "void foo()"?. It may look like typedef void (*action_map[N_INPUTS])(); declares an array of pointers to functions taking no arguments, but it actually declares an array of pointers to functions taking unspecified arguments. This is supported mostly for compatibility with old versions of C and should generally not be used in new programs.
If you do am1[0](1,2,3); you will not get a compile error, and the compiler will happily attempt to pass three arguments to the function one that is not supposed to take any. This is undefined behavior. On some platforms, they might just be ignored, but you won't be alerted that you probably meant something else. On other platforms this may crash or worse. For instance, on a system using a calling convention where the called function is supposed to pop the stack (like the stdcall convention on Windows 32-bit compilers), calling a function with the wrong number of arguments will corrupt the stack.
So a better choice would be
typedef void (*action_map[N_INPUTS])(void);
Then action_map am1; am1[0](1,2,3); will cause a compiler error.
For consistency, I think it is also best to use void when defining a function with no parameters, e.g. void one(void) { ... }.
I am new to C. Can someone explain me whats the difference between these?
I usually use pointers like this:
int myFunction(int* something) {
...
}
int main() {
int something;
something = 0;
myFunction(&something);
...
}
But I've found code which looks like this:
int myFunction(int& something) {
...
}
int main() {
int something;
something = 0;
myFunction(something);
...
}
It seems like the exactly same thing for me. Is there any difference?
As you mentioned, int myFunction(int& something) { is not valid C. It's a reference, which is used in C++.
C and C++ are different languages, despite the similarity in syntax.
In case, you want to modify the content of something, you need to pass a pointer to it to the called function and operate on the pointer. The pointer itself will be passed by value, but by derefrencing the pointer inside the called function, you can achieve the result of pass by reference.
So your first snippet is valid. You should use that in C.
The former is a pointer, which is valid C.
The latter is a C++ reference, which is not valid C.
The most notable difference is "syntactic sugar". To access the contents of the pointer something, you'll have to type *something. When doing the same to the C++ reference something, you don't need the *.
A more subtle difference is that a pointer can be used for pointer arithmetic. For example, to implement the library function strlen, you could do something like this:
size_t strlen (const char* s)
{
const char* start = s;
while(*s != '\0')
{
s++;
}
return (size_t)(s - start);
}
This wouldn't be possible if s was a reference. You'd have to use separate counters etc.
Note that a C++ reference is 100% functionally equivalent to a read-only pointer:
int* const something // C equivalent of a reference
I'm not sure if the question has asked before, but I couldn't find any similar topics.
I'm struggeling with the following piece of code. The idea is to extend r any time later on without writing lots of if-else statements. The functions (func1, func2...) either take zero or one arguments.
void func1() {
puts("func1");
}
void func2(char *arg){
puts("func2");
printf("with arg %s\n", arg);
}
struct fcall {
char name[16];
void (*pfunc)();
};
int main() {
const struct fcall r[] = {
{"F1", func1},
{"F2", func2}
};
char param[] = "someval";
size_t nfunc = RSIZE(r); /* array size */
for(;nfunc-->0;) {
r[nfunc].pfunc(param);
}
return 0;
}
The code above assumes that all functions take the string argument, which is not the case. The prototype for the pointer function is declared without any datatype to prevent the incompatible pointer type warning.
Passing arguments to functions that do not take any parameters usually results in too few arguments. But in this case the compiler doesn't 'see' this ahead, which also let me to believe that no optimization is done to exclude these unused addresses from being pushed onto the stack. (I haven't looked at the actual assemble code).
It feels wrong someway and that's usually a recipe for buffer overflows or undefined behaviour. Would it be better to call functions without parameters separately? If so, how much damage could this do?
The way to do it is typedef a function with 1 argument, so the compiler could verify if you pass the correct number of arguments and that you do not pass something absolutely incompatible (e.g. a struct by value). And when you initialize your array, use this typedef to cast function types.
void func1(void) { ... }
void func2(char *arg) { ... }
void func3(int arg) { ... }
typedef uintptr_t param_t;
typedef void (*func_t)(param_t);
struct fcall {
char name[16];
func_t pfunc;
};
const struct fcall r[] = {
{"F1", (func_t) func1},
{"F2", (func_t) func2}
{"F3", (func_t) func3}
};
...
r[0].pfunc((param_t) "foo");
r[1].pfunc((param_t) "bar");
r[2].pfunc((param_t) 1000);
Here param_t is defined as uintpr_t. This is an integer type big enough to store a pointer value. For details see here: What is uintptr_t data type.
The caveat is that the calling conventions for param_t should be compatible with the function arguments you use. This is normally true for all integer and pointer types. The following sample is going to work, all the type conversions are compatible with each other in terms of calling conventions:
// No problem here.
void ptr_func(struct my_struct *ptr) {
...
}
...
struct my_struct struct_x;
((func_t) &ptr_func)((param_t) &struct_x);
But if you are going to pass a float or double argument, then it might not work as expected.
// There might be a problem here. Depending on the calling
// conventions the value might contain a complete garbage,
// as it might be taken from a floating point register that
// was not set on the call site.
void float_func(float value) {
...
}
...
float x = 1.0;
((func_t) &float_func)((param_t) x);
In this case you might need to define a function like this:
// Problem fixed, but only partially. Instead of garbage
// there might be rounding error after the conversions.
void float_func(param_t param) {
float value = (float) param;
...
}
...
float x = 1.234;
((func_t) &float_func)((param_t) x);
The float is first being converted to an integer type and then back. As a result the value might be rounded. An obvious solution would be to take an address of x and pass it to modified a function float_func2(float *value_ptr). The function would dereference its pointer argument and get the actual float value.
But, of course, being hardcore C-programmers we do not want to be obvious, so we are going to resort to some ugly trickery.
// Problem fixed the true C-programmer way.
void float_func(param_t param) {
float value = *((float *) ¶m);
...
}
...
float x = 1.234;
((func_t) &float_func)(*((param_t *) &x));
The difference of this sample compared to passing a pointer to float, is that on the architecture (like x86-64) where parameters are passed on registers rather than on the stack, a smart enough compiler can make float_func do its job using registers only, without the need to load the parameter from the memory.
One option is for all the functions accept a char * argument, and your calling code to always pass one. The functions that don't need an argument need not use the argument they receive.
To be clean (and avoid undefined behaviour), if you must have some functions that accept no argument and some functions that accept an argument, use two lists and register/call each type of function separately.
If the behaviour is undefined there's no telling how much damage could be caused.
It might blow up the planet. Or it might not.
So just don't do it, OK?
I'm having trouble returning a void pointer to another function in C.
HEADER FILE:
void *function2( void );
MAIN.C
#include "myHeader.h"
void function1 (){
void *temp = NULL;
temp = function2();
}
FUNCTION2.C
int a = 3;
void *function2(void){
printf("Memory Address %p\n",&a );
return (void *) &a; // value of &a is 0x100023444
}
However, the value of temp in function1() is 0x3444,instead of 0x100023444.
Does anyone know a solution for this, or if I am doing something wrong?
EDITED:
It seems, the header was added in the wrong place, leading to the problem described by AndreyT and Jonathan below, which seems to have fixed the truncation problem. Thanks for your help guys!
Given the revision to the question, I'm confident the problem is that you did not declare function2() before you used it. Consequently, the compiler thinks it returns an int, not a void *. It should also be complaining about the actual definition not matching the assumed declaration.
You should make sure your compiler options require you to define or declare a full prototype for each function before you use it.
Note that you should declare void *function2(void); because omitting the void in the parameter list means something quite different — it means the compiler is not told anything about what parameters it takes, not that it takes no parameters. (This is a difference from C++.)
You still have problems because you're returning a pointer to a local variable. You can probably print the pointer (though even that is not guaranteed by the standard), but you cannot reliably use it.
extern void *function2(void);
void function1(void)
{
void *temp = function2();
printf("Address: %p\n", temp);
}
void *function2(void)
{
int a = 3;
printf("Address: %p\n", &a);
return &a; // value of &a is 0x1200001234
}
Or define function2() before defining function1().
Note that it is crucial to include the header both where the function is defined (to make sure the definition is consistent with the header) and where the function is used (to make sure the use is consistent with the header). As long as you do this, all will be well.
Inside function1 you are calling a yet-undeclared function function2. In classic C language (C89/90) this is allowed, but an undeclared function is assumed to return an int. Apparently, on your platform pointers are 64 bits wide and int is 32 bits wide. This is what causes a truncation of your 64-bit pointer value 0x1200001234 to 32 bits, giving you 0x1234.
Formally, your code has undefined behavior, since after causing the compiler to assume that function2 returns int you declared it as returning void *. Even C89/90 compilers usually issue a warning about this problem (and C99 compiler report an error). Did you ignore it?
Either move the entire definition of function2 up and place it above function1
void *function2(void) {
int a = 3;
return &a;
}
void function1 (void){
void *temp = NULL;
temp = function2();
}
Or, alternatively, declare function2 before calling it
void *function2(void);
void function1(void) {
void *temp = NULL;
temp = function2();
}
void *function2(void) {
int a = 3;
return &a;
}
You have to declare your functions before you call them (preferably with prototype).
This answer is apart from truncation.
In function2() a is local variable. Here scope and lifetime od a limited to the function2. So returning the address to other function is illegal. It will cause undefined behavior. Please pay more attention to learn storage class in C
I have the following question:
Is it possible to cast pointer "on the fly", without additional variable assignment? Let's see some example:
typedef struct
{
uint8_t TimeSlot;
uint8_t TimeTick;
}Menager_t;
void SomeFunction(void* vp)
{
(Menager_t *)vp->TimeSlot = 0; //Error, request for member 'TimeSlot'
//in something not a structure or union
}
So, this can be solved by assign void pointer to temporary pointer inside of function, like this:
void SomeFunction(void* vp)
{
Menager_t *temp = vp;
temp->TimeSlot = 0;
}
But i must say that this solution does not satisfy me and looks dirty form me (omitting fact of 128 bytes RAM memory on uC I'm programming) and furthermore I remember that i was doing such things in past...
I'm asking You guys kindly for help in that :)
Regards!
PS: GCC 4.7.2 in use
You forgot to add some parenthesis.
((Menager_t *)vp)->TimeSlot = 0;
-> binds more strongly that (cast) operator, therefore vp->TimeSlot is evaluated first.
-> has higher precendence than the cast (see, e.g., here: http://en.cppreference.com/w/c/language/operator_precedence), so the compiler tries to access TimeSlot on a void *. Add parentheses to make the cast happen first:
((Menager_t *)vp)->TimeSlot = 0;