Array as function with arguments? - c

I'm trying to learn c, so I tried reading some source code.
But I have no idea what this might mean:
static const char*(*const functab[])(void)={
ram,date
};
The first part, static const char* is fine, as it seems to be a function (has an argument of type void), static should mean that it is only visible in this file and const char* should mean that the value cannot be changed but the address can be changed.
But in that case, it doesn't make sense after the last part following the function name, as it was the case with
static const char * date(void);
static const char * ram(void);
Instead of the function name there is (*const functab[]), a const array called functab containing addresses?
Is this some kind of wrapping function containing the functions ram and date? Some alternative way of declaring arrays?

functab is an array of function pointers (array of const function pointers, to be exact), which returns const char* and accepts no arguments.
Later,
... = { ram, date };
is a brace-enclosed initializer list which serves as the initializer for the array.

This is the way to define array of function pointers in C. So instead of calling function as ram(), using this array you can call it by (* functab[1]).
Below discussion has good examples of array of function pointer:
How can I use an array of function pointers?

Short answer: Here functab is an array of function pointers, and the array is initialized with pointers to functions ram and date. This also explains the name functab which is likely from "FUNCtion TABle".
Long answer: In C you can get a pointer to a function and save it to a variable. A variable used in this fashion is known as a function pointer.
For example, funcptr variable below will contain the address of do_stuff's entry point:
int do_stuff(const char* x) { ...do stuff.. }
...
ftype_t funcptr = &do_stuff;
...
(*funcptr)("now"); // calls do_stuff()
This will only work if you have already defined the type of funcptr, which is ftype_t here. The type definition should take this form:
typedef int (*ftype_t)(const char*);
In English, this means ftype_t is being defined as a type of function that takes const char* as its only argument and returns int.
If you didn't want to typedef only for this, you could have achieved the same thing by doing below:
int (*funcptr)(const char*) = &do_stuff;
This works, but its syntax is confusing. Also it gets quite ugly if you attempt to do something like building an array of function pointers, which is exactly what your code does.
Shown below is equivalent code, which is much easier to understand:
typedef static const char*(*myfn_t)(void);
const myfn_t functab[] = { &ram, &date };
(The & (address of) is usually optional, but recommended. )

Complex variable declarations need to be read inside out in C:
functab is the identifier of the variable, so we start reading here...
functab[] it is an array...
*const functab[] of constant pointers...
(*const functab[])(...) to functions...
(*const functab[])(void) that take no arguments...
const char*(*const functab[])(void) but return a const char*.
The meaning of static depends on whether it's outside or inside of a function. If it's outside, the static means that functab is declared with file scope (i.e. a global variable that's only visible inside a single .c file). If it's inside a function, it means that functab is a global variable that's only visible inside that function.
The = { ram, date } initialize the array with two members. Both ram and date should be functions that are declared as const char* ram(void).
The effect of this declaration is, that the following function calls are equivalent:
const char* result = ram();
const char* result = functab[0]();

Related

strange c statement as field in a struct

First of all I am not a C expert but I thought I'd be able to break down C code. I am currently reading some open source repo and have no idea what the following statement within some struct in a header file means:
struct some_struct{
...
/* Callback when non-reply message comes in (inside db transaction) */
void (*billboardcb)(void *channel, bool perm, const char *happenings);
...
}
I thought functions cannot be declared like methods within structs. But if this is a variable (called billboardcb) why are there all these paremeters? I did not find a macro called billboardcb in this code base.
A function pointer is a pointer that stores an address to a function. Function pointers can live inside structs just like any other pointer. The (void *channel, bool perm, const char *happenings) parameters listed after void (*billboardcb) are the function's parameters. The void preceding the (*billboardcb) pointer indicates that the function returns nothing.
If you search for where the some_struct struct is instantiated, you'll likely find the actual function assigned to this pointer. The function assigned to the pointer will be declared like any other function, with its address then stored in the struct by assigning the function's memory address to the struct's pointer.
It's a pointer to function, the function pointer is called billboardcb. The pointer can only point to a function with the 3 parameters that are:
1) void*
2) bool
3) const char *
The pointer can be assigned by just giving it an address of another function with compatible format.

What is meaning of a pointer to a constant function?

Pointers can be declared as pointing to mutable (non-const) data or pointer to constant data.
Pointers can be defined to point to a function.
My coworkers and I were discussing the use of "const" with pointers and the question came up regarding the use of const with function pointers.
Here are some questions:
What is the meaning of a pointer to a constant function versus a
pointer to a non-constant function?
Can a function be const?
Can a function be non-const (mutable)?
What is the proper (safe) syntax for passing a function pointer?
Edit 1: Function pointer syntax
typedef void (*Function_Pointer)(void); // Pointer to void function returning void.
void function_a(Function_Pointer p_func); // Example 1.
void function_b(const Function_Pointer p_func); // Example 2.
void function_c(Function_Pointer const p_func); // Example 3.
void function_d(const Function_Pointer const p_func); // Example 4.
The above declarations are examples of treating a function pointer like a pointer to an intrinsic type.
A data, variable or memory pointer allows for the above combinations.
So the questions are: can a function pointer have the same combinations and what is meant by a pointer to a const function (such as Example 2)?
In C, there's no such thing as a function being const or otherwise, so a pointer to a const function is meaningless (shouldn't compile, though I haven't checked with any particular compiler).
Note that although it's different, you can have a const pointer to a function, a pointer to function returning const, etc. Essentially everything but the function itself can be const. Consider a few examples:
// normal pointer to function
int (*func)(int);
// pointer to const function -- not allowed
int (const *func)(int);
// const pointer to function. Allowed, must be initialized.
int (*const func)(int) = some_func;
// Bonus: pointer to function returning pointer to const
void const *(*func)(int);
// triple bonus: const pointer to function returning pointer to const.
void const *(*const func)(int) = func.
As far as passing a pointer to a function as a parameter goes, it's pretty simple. You normally want to just pass a pointer to the correct type. However, a pointer to any type of function can be converted to a pointer to some other type of function, then back to its original type, and retain the original value.
According to the C spec (C99, section 6.7.3):
The properties associated with qualified types are meaningful only for
expressions that are lvalues.
When the spec says "qualified types", it means things defined with the const, restrict, orvolatile keyword. Snice functions are not lvalues, the const keyword on a function isn't meaningful. You may be looking at some sort of compiler-specific extension. Some compilers will throw an error if you try to declare a function as const.
Are you sure that you're looking at a pointer to a constant function and not a constant pointer to a function (that is, it's the pointer that's const, not the function)?
Regarding #4: see this guide for a helpful overview of creating, passing, and using function pointers.
Under C, there is no such thing as a const function. const is a type-qualifier, and so can only be used to qualify a type, not a function. Maybe you mean a const pointer to a function or a non-const pointer to a function?
In C++, methods can be const. If a method is const, it means that after you call that method, the object containing the method will be in the same state as before you called the method (none of the instance variables[1] have been modified). Thus, you can point to a const method and a non-const method, and those methods are different.
You can accept a function pointer in an argument list as retType (*variableName)(arguments).
[1] Unless they are mutable.
In C, functions can be const if you are in the world of GCC! Functions can be declared const through the use of attributes attached to declarations of functions and other symbols. It is basically used to provide information to the compiler on what the function does, even though its body is not available so that the compiler can do some kind of optimizations with it.
A constant function is generally defined in terms of a pure function.
A pure function is a function with basically no side effect. This
means that pure functions return a value that is calculated based on
given parameters and global memory, but cannot affect the value of any
other global variable. Pure functions cannot reasonably lack a return
type (i.e. have a void return type).
And now we can define what is a const function,
A pure function that does not access global memory, but only its
parameters, is called a constant function. This is because the
function, being unrelated to the state of global memory, will always
return the same value when given the same parameters. The return value
is thus derived directly and exclusively from the values of the
parameters given.
Here const doesn't imply anything about function mutability. But it is a function which doesn't touch global memory. You can assign normal pointers to such functions. Anyways the code region will generally ( forgetting self modifying code for a while ) be RO and you cannot modify it through the normal pointer.
Read the full insightful article here.
So when it comes to GCC Constant functions we are talking about optimizations and not function mutability.
1.What is the meaning of a pointer to a constant function versus a pointer to a non-constant function?
There is no difference between const and non-const: the function itself is not modifiable
Note: In C++ if the function is a member function of a class, const means that the state of the object within this function cannot be changed (member variables assigned to, non-const memeber functions called). In this case the const keyword is part of the member function's signature and therefore makes a difference in terms of the pointer.
2.Can a function be const?
See above.
3.Can a function be non-const (mutable)?
See above
4.What is the proper (safe) syntax for passing a function pointer?
All pointers to free functions can be cast to any other pointer to free function (i.e. their size is the same). So you could define a type for a (hypothetical) function: void f(); and convert all function pointers to this type to store. Note that you should not call the function via this common type: you need to cast it bact to its original pointer-to-function type, otherwise you get undefined behavior (and most likely crash)
For C++: pointers to member functions are not guaranteed to be convertible to pointers to free functions
1.
There is syntactically nowhere to place 'const' to make a function's contents constant.
You will run into 'function is not an l-value' error regardless if you have const or not.
typedef void (* FUNC)(void);
FUNC pFunc;
pFunc = 0; // OK
*pFunc = 0; // error: Cannot assign to a function (a function is not an l-value)
typedef void (* const FUNC)(void);
FUNC pFunc;
pFunc = 0; // error (const)
*pFunc = 0; // error: Cannot assign to a function (a function is not an l-value)
typedef void (const * FUNC)(void); // error: <cv-qualifier> (lol?)
2 & 3.
Function pointers- yes.. Function contents, doesn't look like.
4.
I don't think there is any way to make passing a function pointer safer. With all the consts in the world, the only thing you can protect is that 'SetCallback' can't change it's own local copy of the parameter.
typedef void (* const FUNC)(void);
void SetCallback(const FUNC const pCallback)
{
FUNC pTemp = pCallback; // OK (even though pTemp is not const!!)
pCallback = 0; // error (const)
}

Declaring a pointer to const or a const pointer to const as a formal parameter

I was recently making some adjustments to code wherein I had to change a formal parameter in a function. Originally, the parameter was similar to the following (note, the structure was typedef'd earlier):
static MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
The change was made because I could define and initialize my_special_structure before compile time and myFunction never changed the value of it. This led to the following change:
static const MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (const MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
I also noticed that when I ran Lint on my program that there were several Info 818's referencing a number of different functions. The info stated that "Pointer parameter 'x' (line 253) could be declared as pointing to const".
Now, I have two questions in regards to the above. First, in regards to the above code, since neither the pointer nor the variables within MySpecialStructure is changed within the function, is it beneficial to declare the pointer as constant as well? e.g. -
int myFunction (const MySpecialStructure * const p_structure, unsigned char useful_char)
My second question is in regards to the Lint information. Are there any benefits or drawbacks to declaring pointers as a constant formal parameter if the function is not changing its value... even if what you are passing to the function is never declared as a constant? e.g. -
static unsigned char my_char;
static unsigned char * p_my_char;
p_my_char = &my_char;
int myFunction (const unsigned char * p_char)
{
...
}
Thanks for your help!
Edited for clarification -
What are the advantages of declaring a pointer to const or a const pointer to const- as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
What are the advantages of declaring a pointer as a const - as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
I assumed you meant a pointer to const.
By have a pointer to const as a parameter, the advantage is you document the API by telling the programmer your function does not modify the object pointed by the pointer.
For example look at memcpy prototype:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
It tells the programmer the object pointed to by s2 will not be modified through memcpy call.
It also provides compiler enforced documentation as the implementation will issue a diagnostic if you modify a pointee from a pointer to const.
const also allows to indicate users of your function that you won't modify this parameter behind their back
If you declare a formal parameter as const, the compiler can check that your code does not attempt to modify that parameter, yielding better software quality.
Const correctness is a wonderful thing. For one, it lets the compiler help keep you from making mistakes. An obvious simple case is assigning when you meant to compare. In that instance, if the pointer is const, the compiler will give you an error. Google 'const correctness' and you'll find many resources on the benefits of it.
For your first question, if you are damn sure of not modifying either the pointer or the variable it points to, you can by all means go ahead and make both of them constant!
Now, for your Qn as to why declare a formal pointer parameter as const even though the passed pointer is not constant, A typical use case is library function printf(). printf is supposed to accept const char * but the compiler doesn't complain even if you pass a char* to it. In such a case, it makes sense that printf() doesn't not build upon the user's mistake and alter user's data inadvertantly! Its like printf() clearly telling- Whether you pass a const char * or char*, dont worry, I still wont modify your data!
For your second question, const pointers find excellent application in the embedded world where we generally write to a memory address directly. Here is the detailed explanation
Well, what are the advantages of declaring anything as a const while you have the option to not to do so? After all, if you don't touch it, it doesn't matter if it's const or not. This provides some safety checks that the compiler can do for you, and it gives some information of the function interface. For example, you can safely pass a string literal to a function that expects a const char *, but you need to be careful if the parameter is declared as just a char *.

Defining const pointer to a const string

Readed bog of Ulrich Drepper and come across 2 entries that looks like conficting.
In the first one (string in global space) Ulrich states that the string should be defines as:
const char _pcre_ucp_names[] = "blabla";
while already in second one (string in function) he argues it should be declared as:
static const char _pcre_ucp_names[] = "blabla";
Can you explain what is the better name to declate a string?
UDP:
First of all I removed C++ tag - this question is valid for C as well for C++. So I don't think answers which explain what static means in class/function/file scope is relevant.
Read the articles before answering. The articles deal about memory usage - where the actual data is stored (in .rodata or in .data section), do the string should be relocated (if we're talking about unix/linux shared objects), is it possible to change the string or not.
UDP2
In first one it's said that for global variable following form:
(1) const char *a = "...";
is less good than
(2) const char a[] = "..."
Why? I always thought that (1) is better, since (2) actually replicate the string we assign it, while (1) only points to string we assign.
It depends—if you need the string to be visible to other source files in a project, you can't declare it static. If you only need to access it from the file where it's defined, then you probably want to use static.
The blog post you mention was talking about something different, though:
#include <stdio.h>
#include <string.h>
int main(void)
{
const char s[] = "hello"; /* Notice this variable is inside a function */
strcpy (s, "bye");
puts (s);
return 0;
}
In that case, static means something different: this creates a variable that persists across multiple calls to the same function. His other example showed a global variable, outside of a function.
EDIT:
To clarify, since you edited your question, the reason you don't want to use const char *a = "string" is you create an extra writable pointer. This means that, while you can't change the characters of the string, you can still make the pointer point to an entirely different string. See below:
const char *hello = "hello";
int main( int argc , char const *argv[] )
{
hello = "goodbye";
puts(hello);
return 0;
}
That example compiles and runs. If hello is supposed to be constant, this is surely not what you want. Of course, you can also get around this by writing this:
const char * const hello = "hello";
You still have two variables where you only needed one though -- hello is a pointer to a string constant, where if it's an array there isn't that extra pointer in the way.
Declaring it static means (if at global, file level) that it won't be visible outside this translation unit, or (if inside a scope) that it will retain its value between executions of the scope. It has nothing to do with the "constness" of the data.
While this is indeed a const string, it's neither a pointer nor a const pointer nor is the second one a declaration.
Both define (and initialize) a constant array of characters.
The only difference is that the first one will be visible and accessible from other translation units (proper declarations assumed), while the second one won't.
Note that, in C++, instead of making variables and constants static, you could put them into an unnamed namespace. Then, too, they are inaccessible from other translation units.
On the
const char *abc = "..."; and <br/>
const char def[] = "..."
part of the question...
The only difference to my knowledge is that the array-style definition is not demoted to a pointer when using the sizeof operator.
sizeof(abc) == size of pointer type <br/>
sizeof(def) == size of string (including \0)
Is it for use at a global (file) level or within a class or within a function ? The meaning of static differs ..
For a file level: It depends on the scope you want (either global or limited to the file). No other difference.
For a class: It's best with the static if you're not gonna change it. Because a const can still be redefined on the constructor so it will have to allocate space for a pointer inside the class itself if it's not static. If it is static then no need for a pointer in each class.
For a function: Doesn't really change anything important I think. In the non static case, a pointer will be allocated on the stack and initialized to point in .rodata at each function call. In the other case, it's more like a global variable but with limited scope.

How does one declare an array of constant function pointers in C?

I need to declare an array of pointers to functions like so:
extern void function1(void);
extern void function2(void);
...
void (*MESSAGE_HANDLERS[])(void) = {
function1,
function2,
...
};
However, I want the the array to be declared as constant -- both the data in the array and the pointer to the data. Unfortunately, I do not recall where to place the const key-word(s).
I'm assuming the actual pointer, MESSAGE_HANDLERS in this case, is already constant because it is declared as an array. On the otherhand, couldn't the function pointers within the array be change at runtime if it is declared as shown?
There is a technique to remember how to build such type. First try to read pointers starting from their name and read from right to left.
How to declare that stuff without help?
Arrays
T t[5];
is an array of 5 T. To make T a function type, you write the return-type to the left, and the parameters to the right:
void t[5](void);
would be an array of 5 functions returning void and taking no parameters. But functions itself can't be stuffed in arrays! They are not objects. Only pointers to them can.
What about
void * t[5](void);
That's still wrong as it would just change the return-type to be a pointer to void. You have to use parentheses:
void (*t[5])(void);
and this will actually work. t is an array of 5 pointers to functions returning void and taking no parameters.
Great! What about an array of pointers to arras? That's very similar. The element type appears at the left, and the dimension at the right. Again, parentheses are needed because otherwise the array would become a multidimensional array of integer pointers:
int (*t[5])[3];
That's it! An array of 5 pointers to arrays of 3 int.
What about functions?
What we have just learned is true about functions too. Let's declare a function taking an int that returns a pointer to another function taking no parameter and returning void:
void (*f(int))(void);
we need parentheses again for he same reason as above. We could now call it, and call the returned function pointed to again.
f(10)();
Returning a pointer to function returning another pointer to function
What about this?
f(10)(true)(3.4);
? In other words, how would a function taking int returning a pointer to a function taking bool returning a pointer to a function taking double and returning void would look like? The answer is that you just nest them:
void (*(*f(int))(bool))(double);
You could do so endless times. Indeed, you can also return a pointer to an array just like you can a pointer to a function:
int (*(*f(int))(bool))[3];
This is a function taking int returning a pointer to a function taking bool returning a pointer to an array of 3 int
What does it have to do with const?
Now that the above explained how to build up complexer types from fundamental types, you can put const at places where you now know where they belong to. Just consider:
T c * c * c ... * c name;
The T is the basic type that we end up pointing to at the end. The c stands for either const or not const. For example
int const * const * name;
will declare name to have the type pointer to a constant pointer to a constant int. You can change name, but you cannot change *name, which would be of type
int const * const
and neither **name, which would be of type
int const
Let's apply this to a function pointer of above:
void (* const t[5])(void);
This would actually declare the array to contain constant pointers. So after creating (and initializing) the array, the pointers are const, because the const appeared after the star. Note that we cannot put a const before the star in this case, since there are no pointers to constant functions. Functions simply can't be const as that would not make sense. So the following is not valid:
void (const * t[5])(void);
Conclusion
The C++ and C way of declaring functions and arrays actually is actually a bit confusing. You have to get your head around it first, but if you understand it, you can write very compact function declarations using it.
In situations like this, do a typedef to name your function signature, that makes it far simpler:
typedef void MESSAGE_HANDLER(void);
with that in place, it should be just:
MESSAGE_HANDLER * const handlers[] = { function1, function2 };
To get the actual content of the array constant.
EDIT: Removed pointer part from the typedef, this really is better (live and learn).
cdecl says:
cdecl> explain void (* const foo[])(void)
declare foo as array of const pointer to function (void) returning void
Is it what you need?
With VisualStudio 2008, I get:
void (* const MESSAGE_HANDLERS[])(void) = {
NULL,
NULL
};
int main ()
{
/* Gives error
'=' : left operand must be l-value
*/
MESSAGE_HANDLERS = NULL;
/* Gives error
l-value specifies const object
*/
MESSAGE_HANDLERS[0] = NULL;
}
I am not sure if this will work in 'C'. it does work in 'C++':
First define MESSAGE_HANDLERS as a type:
typedef void (*MESSAGE_HANDLER)();
Then, use the type definition to declare your array a constant:
MESSAGE_HANDLER const handlers[] = {function1, function2};
The trick is in the typedef, if you can do the same semantically in 'C', it should work too.

Resources