I'm a new C programmer and I'm writing some data structures for homework.
I have two questions here.
We see a lot of examples of C's function-pointers, usually used to save code duplication. I messed around with this function, which I initially wrote:
(The constants we're pre #defined. Indentation is off, too).
static PlayerResult playerCheckArguments(const char* name, int age,
int attack, int defense) {
PlayerResult result = PLAYER_SUCCESS;
if (!name) {
result = PLAYER_NULL_ARGUMENT;
} else if (strlen(name) > PLAYER_MAX_NAME_LENGTH) {
result = PLAYER_NAME_TOO_LONG;
} else if (invalidAge(age)) {
result = PLAYER_INVALID_AGE;
} else if (invalidAttack(attack)) {
result = PLAYER_INVALID_ATTACK;
} else if (invalidDefense(defense)) {
result = PLAYER_INVALID_DEFENSE;
}
return result;
}
until I got this ghoul:
static PlayerResult playerCheckArguments(const char* name, int age, int attack,
int defense) {
void* arguments[PLAYER_NUM_OF_PAREMETERS] = { name, &age, &attack, &defense };
PlayerResult (*funcArray[PLAYER_NUM_OF_PAREMETERS])(
int) = {&invalidName, &invalidAge, &invalidAttack, &invalidDefense };
PlayerResult result = PLAYER_SUCCESS;
for (int i = 0;
i < PLAYER_NUM_OF_PAREMETERS && result == PLAYER_SUCCESS; i++) {
PlayerResult (*func)(int) = funcArray[i];
void* key = arguments[i];
result = func(key);
}
return result;
My first question being - is there any reason why I should use/write the second function over the other, and generally try to use such "sophistications" which obviously lessen the code's clarity and/or simplicity?
now, for my second question: As you may have noticed, I am using a lot of local variables for the purpose of easier debugging. this way, I can see all relevant evaluations and efficiently monitor the program as it runs.
Is there any other way to display expressions made in a function other than using local variables?
Thanks very much!
return 0 ;-)
Clarity is far more important than cleverness. The harder it is to figure out the harder it is to get right, and to debug when you don't.
There is nothing wrong with using local variables for clarity or debugging. There is an ole saw that goes "Avoid the sin of premature optimization". Make your code as simple and as clear as you can. If you then find that isn't enough work to add as little complexity as needed to get the job done.
Since your question is tagged coding style, I'll just say, the first is definitely preferred. The reason is simple. Show the two functions to 200 programmers, 100 see the first, 100 see the second, and then record the average time it takes for the programmers to be able to describe what the function does. you'll absolutely, averaged over hundreds of programmers, find that the first wins every time.
So you would only do the second if perhaps you had 20+ different parameters to check, and even then there are cleaner ways to do it. I don't believe you'd see any speed increase for the second one either.
Related
I want to write a function that will take two integers, three times, and then return them ordered by the first integer and (for now) print them in main (though eventually I plan/hope to switch to a file-based structure to store and organize data), but I think I might have an issue with my pointers cause even when I skip concatenations (which looks like might also be another separate issue), everything Ive tried has main print a string (or no string) which never matches the input, but the print statements suggest all the looped assignments are working properly.
#include <stdio.h>
#include <string.h>
const char * entry()
{
int n;
int level;
char habit1entry[6];
char habit2entry[6];
char habit3entry[6];
for (int c = 0; c< 3; c++){
printf("Habit #\n");
scanf("%d", &n);
printf("Level:\n");
scanf("%d", &level);
switch (n)
{
case 1:;
sprintf(habit1entry, "|%d|%d|\n", n,level);
printf("n = %d\n",n);
printf("%s\n",habit1entry);
continue;
case 2:;
sprintf(habit2entry, "|%d|%d|\n", n,level);
printf("n = %d\n",n);
printf("%s\n",habit2entry);
continue;
case 3:;
sprintf(habit3entry, "|%d|%d|\n", n,level);
printf("n = %d\n",n);
printf("%s\n",habit3entry);
continue;
}
}
strcat(habit2entry,habit3entry);
printf("%s\n",habit2entry);
strcat(habit1entry,habit2entry);
printf("%s\n",habit1entry);
char *fullEntry=habit3entry;
printf("%s\n",fullEntry);
return strdup(&fullEntry[0]);
}
int main(){
const char * dataEntry = entry();
//strcpy(dataEntry,entry());
printf("Data:\n%s",dataEntry);
}
heres an example of the output(after the correct prints inside the switch cases) for an input of 3 2 1 1 2 2:
"
|2|2|
|1|1|
|2|2|
|2|2|
|��
|2|2|
|��
* stack smashing detected *: ./a.out terminated
Aborted (core dumped) "
p.s. Sorry if this all sounds silly, this is my first C project (and first real stack overflow post, plz b gentl) coming from jumping around between java, python and clojure and I would like to take an operating systems class that allows you to start without knowing C but expects you to pick it up on your own and its hard finding material that explains C concepts in a scope that matches my background knowledge and current learning constraints in terms of time available for taking deep dives through explanations that for me have ended up mostly being either hopelessly esoteric, incredibly case-specific or overly-simplistic/redundant/unhelpful explanations of programming concepts I picked up in other languages. Dont mean to complain or harp on and its probably good to get practice with different methods of asking questions and finding answers for problems like these, but the learning curve for understanding things like this (setting up the compiler/json files involved spending hours only to discover that mcafee was deleting my exes which I became convinced was a symptom of a virus, only to have the behavior stop after I restarted for a minor routine windows update and I have no idea why) outside of a traditional framework sometimes seems more like a wall and I'm worried that maybe I should revise my approach to avoid wasting too much of my time banging my head against a series of very sturdy walls. any and all advice is greatly appreciated.
Abstracting form the logic of the program, you have plenty of issues there:
You do not provide enough space for the strings
Your switch is not very related to your for loop
Names of the variables do not matter for you - but they matter for the program . Be more careful.
probably more but I forgot already
#include <stdio.h>
#include <string.h>
const char * entry()
{
int n;
int level;
char habit1entry[21] = "";
char habit2entry[14] = "";
char habit3entry[7] = "";
for (int c = 1; c < 4; c++){
printf("Habit #\n");
scanf("%d", &n);
printf("Level:\n");
scanf("%d", &level);
switch (c)
{
case 1:;
sprintf(habit1entry, "|%d|%d|\n", n,level % 10);
printf("n = %d\n",n);
printf("He1: %s\n",habit1entry);
continue;
case 2:;
sprintf(habit2entry, "|%d|%d|\n", n,level % 10);
printf("n = %d\n",n);
printf("He2 = %s\n",habit2entry);
continue;
case 3:;
sprintf(habit3entry, "|%d|%d|\n", n,level % 10);
printf("n = %d\n",n);
printf("He3 = %s\n",habit3entry);
continue;
}
}
strcat(habit2entry,habit3entry);
printf("H2 + H3 = %s\n",habit2entry);
strcat(habit1entry,habit2entry);
printf("H1 + H2 = %s\n",habit1entry);
char *fullEntry=habit1entry;
printf("FE: %s\n",fullEntry);
return strdup(fullEntry);
}
int main(){
const char * dataEntry = entry();
//strcpy(dataEntry,entry());
printf("Data:\n%s",dataEntry);
}
Welcome to the weird and wonderful world of C.
I have not actually compiled and run your program yet, just had a quick read through and though I give you my first thoughts.
The way your program is written is primed to generate stack overflows. You have three (very little) character arrays defined on the stack habitxentry, so your sprintf's will most certainly blow your stack unless both the Habit and Level inputs are less than 10. Habit is alright because your switch only allows 1, 2 or 3. Your switch does nothing if Habit is anything else.
As a side note: sprintf is not really the function to use in our security minded world. snprintf is a better choice. Not really an issue here per se as you are not passing in user supplied data but still, it's not a good habit to cultivate.
Next you strcat your character arrays together, virtually guarantying a stack violation, but lets assume this works; you are concatenating 2 and 3 into habit2entry and then 1 and 2 into habit1entry.
Next you are creating a pointer to habit3entry (not habit1entry) and returning a duplicate.
By doing so you are allocating heap in a mildy obscure manner. The callee will be responsible for freeing this memory.
I always preferred to explicitly malloc the memory and then strcpy (or memcpy) the data in.
Now when you grep your code, you only have to look for malloc.
Also, someone using the function will notice the malloc, see you have returned to pointer and realize that freeing it will now be his problem.
In order to avoid these problems some programmers leave it to the caller to supply a buffer to the function. The reasoning is that a function is supposed to do one thing and one thing only. In this case you are doing two things, you allocate memory and you fill that memory.
In your switch statement I noticed that each of your case labels are followed by an empty statement.
the semicolon at the end of that line is not necessary: write "case 1:" not "case 1:;"
You also use continue at the end of each block. This is allowed but "break" is more appropriate.
In this case it will have the same effect but normally you have more statements after the switch.
Now the difference will become apparent. Continue will jump straight to the top of the loop, break will break out of the switch and continue executing there.
Hope this gives you some insight.
Good luck.
ok this is one of the functions on the hash program provided by my lecturer.. It has many commands that I've never tried before, like strdup, hash, etc.. from my point of view, this function is used to add the columns to the hash (hash is like tables right??) in the main program there's a repeat of this function using for 5 times because there are 5 table description... so here's the function:
int install (char *name, char *desc){
unsigned int hi;
node *np;
if((np=lookup(name))==NULL){
hi=hash(name);
np=(node*)malloc(sizeof(node));
if (np==NULL){
return 0;
}
np ->name = m_strdup(name);
if (np->name == NULL){
return 0;
}
np -> next=hashtab[hi];
hashtab[hi]=np;
}
else{
free (np->desc);
}
np -> desc=m_strdup(desc);
if (np->desc == NULL){
return 0;
}
return 1;
}
why are there so many returns?? if the function return 0, it means the function isn't successfully doing what it's supposed to right?? if it already returns 0, is it possible for the function to return 1?? well i'm totally noob at this.. Thanks for your kind help :D
That function as written will return 0 if something went wrong and 1 otherwise. This is a reasonably common but by no means universal idiom.
Regarding the multiple return statements only one of them will be executed for a particular call to the function, since what return does is stop executing the current function and go back (i.e. return) to the caller. Different calls to the same function can take different paths through the code and therefore hit different return statements, but any single call will only hit one return.
The use of multiple return statements in a method is a commonly debated style issue. It can arguably make code both easier and harder to read depending on how it's done. See this question & this question for some views on that.
edit: Thanks to all repliers. I should have mentioned in my original post that I am not allowed to change any of the specifications of these functions, so solutions using assertions and/or allowing to dereference NULL are out of the question.
With this in mind, I gather that it's either I go with a function pointer, or just leave the duplication as it is. For the sake of clarity I'd like to avoid function pointers this time.
original:
I am trying to avoid code duplication without losing clarity.
often when working on a specific assignment (Uni - undergrad) I recognize these patterns of functions return , but not always with a "great-job" solution..
What would any of you suggest I should do (pointers to functions, macros, etc.) with these three C functions that check some of their arguments in the same way to make the checking more modular (it should be more modular, right?)?
BTW these are taken directly from a HW assignment, so the details of their functionality are not concerning my question, only the arguments checking at the function's top.
teamIsDuplicateCoachName(Team team, bool* isDuplicate) {
TeamResult result = TEAM_SUCCESS;
if (!team || !isDuplicate) {
result = TEAM_NULL_ARGUMENT;
} else if (teamEmpty(team)) {
result = TEAM_IS_EMPTY;
} else {
for (int i = 0; i < team->currentFormations; ++i) {
if (teamIsPlayerInFormation(team->formations[i], team->coach)) {
*isDuplicate = true;
break;
}
}
}
return result;
}
TeamResult teamGetWinRate(Team team, double* winRate) {
TeamResult result = TEAM_SUCCESS;
if (!team || !winRate) {
result = TEAM_NULL_ARGUMENT;
} else {
int wins = 0, games = 0;
for (int i = 0; i < team->currentFormations; ++i) {
Formation formation = team->formations[i];
if (formationIsComplete(formation)) {
games += formation->timesPlayed;
wins += formation->timesWon;
}
}
double win = ( games == 0 ) ? 0 : (double) wins / games;
assert(win >= 0 && win <= 1);
*winRate = win;
}
return result;
}
TeamResult teamGetNextIncompleteFormation(Team team, Formation* formation,
int* index) {
TeamResult result = TEAM_SUCCESS;
if (!team || !formation || !index) {
result = TEAM_NULL_ARGUMENT;
} else {
*formation = NULL; /* default result, will be returned if there are no incomplete formations */
for (int i = 0; i < team->currentFormations; ++i) {
Formation formationPtr = team->formations[i];
if (!formationIsComplete(formationPtr)) {
*formation = formationPtr;
*index = i;
break;
}
}
}
return result;
}
Any advice on how (specifically) to avoid the code duplication would be appreciated.
Thanks for your time! :)
It looks like it's a coding mistake to pass nulls to these functions. There's three main ways to deal with this situation.
Handle the erroneous nulls and return an error value. This introduces extra code which checks the arguments to return error values, and extra code around every call site, which now has to handle the error return values. Probably none of this code is tested, since if you knew that code was mistakenly passing nulls you'd just fix it.
Use assert to check validity of arguments, resulting in a clean error message, clear to read preconditions, but some extra code.
Have no precondition checks, and debug segfaults when you deference a NULL.
In my experience 3 is usually the best approach. It adds zero extra code, and a segfault is usually just as easy to debug as the clean error message you'd get from 2. However, you'll find many software engineers who would prefer 2, and it's a matter of taste.
Your code, which is pattern 1, has some significant downsides. First, it's adding extra code which can't be optimised away. Second, more code means more complexity. Third, it's unclear if the functions are supposed to be able to accept broken arguments, or if the code's just there to help debugging when things are wrong.
I would create a function to check the team object:
TeamResult TeamPtrCheck(Team *team)
{
if (team == NULL)
return TEAM_NULL_ARGUMENT;
else if (teamEmpty(team))
return TEAM_IS_EMPTY;
else
return TEAM_SUCCESS;
}
And then reference that + your other checks at the top of each function, for example
TeamResult = TeamPtrCheck(team);
if (TeamResult != TEAM_SUCCESS)
return TeamResult;
if (winRate == NULL)
return TEAM_NULL_ARGUMENT;
Otherwise, if each function is different then leave the checks as different!
If you are concerned about the duplication of the NULL checks at the start of each function, I wouldn't be. It makes it clear to the user that you are simply doing input validation prior to doing any work. No need to worry about the few lines.
In general, don't sweat the small stuff like this.
There are a few techniques to reduce the redundancy you percieve, which one is applicable heavily depends on the nature of the condition you are checking. In any case, I would advise against any (preprocessor) tricks to reduce duplication which hide what is actually happening.
If you have a condition that should not happen, one concise way to check for it is to use an assert. With an assert you basically say: This condition must be true, otherwise my code has a bug, please check if my assumption is true, and kill my program immediately if it's not. This is often used like this:
#include <assert.h>
void foo(int a, int b) {
assert((a < b) && "some error message that should appear when the assert fails (a failing assert prints its argument)");
//do some sensible stuff assuming a is really smaller than b
}
A special case is the question whether a pointer is null. Doing something like
void foo(int* bar) {
assert(bar);
*bar = 3;
}
is pretty pointless, because dereferencing a null pointer will securely segfault your program on any sane platform, so the following will just as securely stop your program:
void foo(int* bar) {
*bar = 3;
}
Language lawyers may not be happy with what I'm saying because, according to the standard, dereferencing a null pointer is undefined behaviour, and technically the compiler would be allowed to produce code that formats your harddrive. However, dereferencing a null pointer is such a common error that you can expect your compiler not to do stupid things with it, and you can expect your system to take special care to ensure that the hardware will scream if you try to do it. This hardware check comes for free, the assert takes a few cycles to check.
The assert (and segfaulting null pointers), however, is only suitable for checking for fatal conditions. If you are just checking for a condition that makes any further work inside a function pointless, I would not hesitate to use an early return. It is usually much more readable, especially since syntax highlighting readily reveals the return statements to the reader:
void foo(int a, int b) {
if(a >= b) return;
//do something sensible assuming a < b
}
With this paradigm, your first function would look like this:
TeamResult teamIsDuplicateCoachName(Team team, bool* isDuplicate) {
if(!team || !isDuplicate) return TEAM_NULL_ARGUMENT;
if(teamEmpty(team)) return TEAM_IS_EMPTY;
for (int i = 0; i < team->currentFormations; ++i) {
if (teamIsPlayerInFormation(team->formations[i], team->coach)) {
*isDuplicate = true;
break;
}
}
return TEAM_SUCCESS;
}
I believe, this is much more clear and concise than the version with the if around the body.
This is more or less a design question. If the functions above are all static functions (or only one is extern), then the whole "bundle of function" should check the condition - execution flow-wise - once for each object and let the implementation details of lower level functions assume that input data is valid.
For example, if you go back to wherever the team is created, allocated and initialized and wherever the formation is created, allocated and initialized and build rules there that ensure that every created team exists and that no duplicate exists, you will not have to valid the input because by definition/construction it will always be. This is examples of pre conditions. Invariants would be the persistance of the truthfulness of these definitions (no function may alter invariant states upon return) and post conditions would be somewhat the opposite (for example when they are free'd but pointers still exists somewhere).
That being said, manipulating "object-like" data in C, my personnal preference is to create extern functions that creates, returns and destroys such objects. If the members are kept static within the .c files with minimal .h interface, you get something conceptually similar to object oriented programming (though you can never make members fully "private").
Thanks to all repliers. I should have mentioned in my original post that I am not allowed to change any of the specifications of these functions, so solutions using assertions and/or allowing to dereference NULL are out of the question, though I'll consider them for other occasions.
With this in mind, I gather that it's either I go with a function pointer, or just leave the duplication as it is. For the sake of clarity I'd like to avoid function pointers this time.
Would it be possible to implement an if that checks for -1 and if not negative -1 than assign the value. But without having to call the function twice? or saving the return value to a local variable. I know this is possible in assembly, but is there a c implementation?
int i, x = -10;
if( func1(x) != -1) i = func1(x);
saving the return value to a local variable
In my experience, avoiding local variables is rarely worth the clarity forfeited. Most compilers (most of the time) can often avoid the corresponding load/stores and just use registers for those locals. So don't avoid it, embrace it! The maintainer's sanity that gets preserved just might be your own.
I know this is possible in assembly, but is there a c implementation?
If it turns out your case is one where assembly is actually appropriate, make a declaration in a header file and link against the assembly routine.
Suggestion:
const int x = -10;
const int y = func1(x);
const int i = y != -1
? y
: 0 /* You didn't really want an uninitialized value here, right? */ ;
It depends whether or not func1 generates any side-effects. Consider rand(), or getchar() as examples. Calling these functions twice in a row might result in different return values, because they generate side effects; rand() changes the seed, and getchar() consumes a character from stdin. That is, rand() == rand() will usually1 evaluate to false, and getchar() == getchar() can't be predicted reliably. Supposing func1 were to generate a side-effect, the return value might differ for consecutive calls with the same input, and hence func1(x) == func1(x) might evaluate to false.
If func1 doesn't generate any side-effect, and the output is consistent based solely on the input, then I fail to see why you wouldn't settle with int i = func1(x);, and base logic on whether or not i == -1. Writing the least repetitive code results in greater legibility and maintainability. If you're concerned about the efficiency of this, don't be. Your compiler is most likely smart enough to eliminate dead code, so it'll do a good job at transforming this into something fairly efficient.
1. ... at least in any sane standard library implementation.
int c;
if((c = func1(x)) != -1) i = c;
The best implementation I could think of would be:
int i = 0; // initialize to something
const int x = -10;
const int y = func1(x);
if (y != -1)
{
i = y;
}
The const would let the compiler to any optimizations that it thinks is best (perhaps inline func1). Notice that func is only called once, which is probably best. The const y would also allow y to be kept in a register (which it would need to be anyway in order to perform the if). If you wanted to give more of a suggestion, you could do:
register const int y = func1(x);
However, the compiler is not required to honor your register keyword suggestion, so its probably best to leave it out.
EDIT BASED ON INSPIRATION FROM BRIAN'S ANSWER:
int i = ((func1(x) + 1) ?:0) - 1;
BTW, I probably wouldn't suggest using this, but it does answer the question. This is based on the SO question here. To me, I'm still confused as to the why for the question, it seems like more of a puzzle or job interview question than something that would be encountered in a "real" program? I'd certainly like to hear why this would be needed.
Greetings and salutations,
I am looking for information regrading design patterns for working with a large number of functions in C99.
Background:
I am working on a complete G-Code interpreter for my pet project, a desktop CNC mill. Currently, commands are sent over a serial interface to an AVR microcontroller. These commands are then parsed and executed to make the milling head move. a typical example of a line might look like
N01 F5.0 G90 M48 G1 X1 Y2 Z3
where G90, M48, and G1 are "action" codes and F5.0, X1, Y2, Z3 are parameters (N01 is the optional line number and is ignored). Currently the parsing is coming along swimmingly, but now it is time to make the machine actually move.
For each of the G and M codes, a specific action needs to be taken. This ranges from controlled motion to coolant activation/deactivation, to performing canned cycles. To this end, my current design features a function that uses a switch to select the proper function and return a pointer to that function which can then be used to call the individual code's function at the proper time.
Questions:
1) Is there a better way to resolve an arbitrary code to its respective function than a switch statement? Note that this is being implemented on a microcontroller and memory is EXTREMELY tight (2K total). I have considered a lookup table but, unfortunately, the code distribution is sparse leading to a lot of wasted space. There are ~100 distinct codes and sub-codes.
2) How does one go about function pointers in C when the names (and possibly signatures) may change? If the function signatures are different, is this even possible?
3) Assuming the functions have the same signature (which is where I am leaning), is there a way to typedef a generic type of that signature to be passed around and called from?
My apologies for the scattered questioning. Thank you in advance for your assistance.
1) Perfect hashing may be used to map the keywords to token numbers (opcodes) , which can be used to index a table of function pointers. The number of required arguments can also be put in this table.
2) You don's want overloaded / heterogeneous functions. Optional arguments might be possible.
3) your only choice is to use varargs, IMHO
I'm not an expert on embedded systems, but I have experience with VLSI. So sorry if I'm stating the obvious.
The function-pointer approach is probably the best way. But you'll need to either:
Arrange all your action codes to be consecutive in address.
Implement an action code decoder similar to an opcode decoder in a normal processor.
The first option is probably the better way (simple and small memory footprint). But if you can't control your action codes, you'll need to implement a decoder via another lookup table.
I'm not entirely sure on what you mean by "function signature". Function pointers should just be a number - which the compiler resolves.
EDIT:
Either way, I think two lookup tables (1 for function pointers, and one for decoder) is still going to be much smaller than a large switch statement. For varying parameters, use "dummy" parameters to make them all consistent. I'm not sure what the consequences of force casting everything to void-pointers to structs will be on an embedded processor.
EDIT 2:
Actually, a decoder can't be implementated with just a lookup table if the opcode space is too large. My mistake there. So 1 is really the only viable option.
Is there a better way ... than a switch statement?
Make a list of all valid action codes (a constant in program memory, so it doesn't use any of your scarce RAM), and sequentially compare each one with the received code. Perhaps reserve index "0" to mean "unknown action code".
For example:
// Warning: untested code.
typedef int (*ActionFunctionPointer)( int, int, char * );
struct parse_item{
const char action_letter;
const int action_number; // you might be able to get away with a single byte here, if none of your actions are above 255.
// alas, http://reprap.org/wiki/G-code mentions a "M501" code.
const ActionFunctionPointer action_function_pointer;
};
int m0_handler( int speed, int extrude_rate, char * message ){ // M0: Stop
speed_x = 0; speed_y = 0; speed_z = 0; speed_e = 0;
}
int g4_handler ( int dwell_time, int extrude_rate, char * message ){ // G4: Dwell
delay(dwell_time);
}
const struct parse_item parse_table[] = {
{ '\0', 0, unrecognized_action } // special error-handler
{ 'M', 0, m0_handler }, // M0: Stop
// ...
{ 'G', 4, g4_handler }, // G4: Dwell
{ '\0', 0, unrecognized_action } // special error-handler
}
ActionFunctionPointer get_action_function_pointer( char * buffer ){
char letter = get_letter( buffer );
int action_number = get_number( buffer );
int index = 0;
ActionFunctionPointer f = 0;
do{
index++;
if( (letter == parse_table[index].action_letter ) and
(action_number == parse_table[index].action_number) ){
f = parse_table[index].action_function_pointer;
};
if('\0' == parse_table[index].action_letter ){
index = 0;
f = unrecognized_action;
};
}while(0 == f);
return f;
}
How does one go about function pointers in C when the names (and
possibly signatures) may change? If the function signatures are
different, is this even possible?
It's possible to create a function pointer in C that (at different times) points to functions with more or less parameters (different signatures) using varargs.
Alternatively, you can force all the functions that might possibly be pointed to by that function pointer to all have exactly the same parameters and return value (the same signature) by adding "dummy" parameters to the functions that require fewer parameters than the others.
In my experience, the "dummy parameters" approach seems to be easier to understand and use less memory than the varargs approach.
Is there a way to typedef a generic type of that signature
to be passed around and called from?
Yes.
Pretty much all the code I've ever seen that uses function pointers
also creates a typedef to refer to that particular type of function.
(Except, of course, for Obfuscated contest entries).
See the above example and Wikibooks: C programming: pointers to functions for details.
p.s.:
Is there some reason you are re-inventing the wheel?
Could maybe perhaps one of the following pre-existing G-code interpreters for the AVR work for you, perhaps with a little tweaking?
FiveD,
Sprinter,
Marlin,
Teacup Firmware,
sjfw,
Makerbot,
or
Grbl?
(See http://reprap.org/wiki/Comparison_of_RepRap_Firmwares ).