what does this statement in c means? - c

struct abc
{
//some members
}arrayOf[10];
struct def
{
//some data memebers
}obj;
typedef void (*abc) (obj)
I am not sure what does the statement typedef void (*abc) (obj) implies. Please consider that I am new to this.

Even ignoring the missing semicolon, it doesn't mean anything; it's an error.
If obj were a type name, it would define abc as an alias for the type void (*)(obj), i.e., as a pointer to a function taking a single argument of type obj and returning void.
But since obj is an object name, not a type name, that's not actually what it means.
When I compile it with gcc, I get a warning:
warning: parameter names (without types) in function declaration
When I compile with -pedantic-errors, the warning becomes a fatal error.
An old-style (non-prototype) function definition can legally specify names, but not types, for arguments:
void old_style_func(obj)
/* obj is implicitly of type int */
{
}
But that form is not valid for a function declaration. In a declaration, a single identifier between the parentheses has to be a type name, not the name of a parameter -- which makes the declaration a prototype.
gcc's error message implies that it's trying to interpret it as if it were the beginning of an old-style definition, and then deciding that it's invalid because it's just a declaration.
The bottom line is that you should pay close attention to compiler warnings.
We could speculate about what was intended. Perhaps obj was meant to be a type name, and this:
struct def
{
//some data memebers
}obj;
was supposed to be:
typedef struct def
{
// some data members
} obj;
Or perhaps a type name was accidentally omitted, and the last line should have been:
typedef void (*abc) (struct def obj);
though in that case the name obj is being used twice for different purposes (legal, but confusing). But without more context, it's impossible to be sure how to "fix" it.
Where did this code come from? Are you sure you've shown us the exact code? What happened when you tried to compile it?

it defines the type abc as a pointer to a function that accepts one argument of type int called obj and returns nothing (void).

It introduces a new name abc for the type of a pointer to a function that takes an obj and returns void. The type of a pointer-to-function is always specified in this roundabout way in a declaration:
return-type (* name-being-declared)(parameter-list)
Incidentally, the * in the declaration is probably unnecessary. Function types always magically turn into pointer-to-function types when you need them (like how an array type magically turns into a pointer-to-element type), and you can use a function type directly (instead of a pointer-to-function type) to declare a new function.
As others have pointed out, the context you give doesn't have a type named obj, only an object named obj. If this code compiles, there must be another type named obj defined somewhere else, in code you haven't given.

Related

Forward declaration of a function typedef in C

I have a nagging suspicion that this has been asked before, but I'm not finding it...
Suppose I have a typedef for function A that takes a pointer to a function with typedef B, which in turn takes a function of typedef A. If one of these was a struct, I know how I would handle the forward declaration, but for functions I don't know the syntax. Is there one?
I want to be able to do:
typedef void (*function_A_t)(function_B_t f_B);
typedef void (*function_B_t)(function_A_t f_A);
Any hints? Even better, a reference? Incidentally this actually just happened for me, but I was able to fix it another way, although this would actually smoother (better decoupling, less chance of next guy messing it up) if it's possible.
You can do this by taking advantage of the fact that C specifies that a function declaration with no arguments means it takes an indeterminate number of arguments.
So you could do it as follows:
typedef void (*function_A_t)(void (*)());
typedef void (*function_B_t)(function_A_t f_A);
Which allows the following to compile:
void A(function_B_t b)
{
b(A);
}
void B(function_A_t a)
{
a(B);
}
int main()
{
function_A_t a = A;
function_B_t b = B;
a(B);
b(A);
return 0;
}
Section 6.7.6.3p15 of the C standard states the following regarding the compatibility of function types:
For two function types to be compatible, both shall specify
compatible return types. Moreover, the parameter type lists, if
both are present, shall agree in the number of parameters and
in use of the ellipsis terminator; corresponding parameters
shall have compatible types. If one type has a parameter type list
and the other type is specified by a function declarator that is
not part of a function definition and that contains an empty
identifier list, the parameter list shall not have an ellipsis
terminator and the type of each parameter shall be compatible with
the type that results from the application of the default
argument promotions. If one type has a parameter type list and the
other type is specified by a function definition that contains a
(possibly empty) identifier list, both shall agree in the number
of parameters, and the type of each prototype parameter shall
be compatible with the type that results from the application
of the default argument promotions to the type of the
corresponding identifier. (In the determination of type
compatibility and of a composite type, each parameter declared
with function or array type is taken as having the adjusted type
and each parameter declared with qualified type is taken as having the
unqualified version of its declared type.)
The part in bold above specifies that void (*)() is compatible with void (*)(function_B_t)

Declaring pointers to function returning arrays is actually legal?

At least by the C11 standard and from what I've read.
The only place where return type is not allowed to be an array type is in the section of function definitions (at $6.9.1.3):
The return type of a function shall be void or a complete object type
other than array type.
At function calls ($6.5.2.2.1) it states this:
The expression that denotes the called function shall have type
pointer to function returning void or returning a complete object type
other than an array type.
Which means that something like this would be expected:
int (*pf1)()[4]; //legal?
pf1(); //error calling a function which return array
What I mean is that from how I understand the standard only defining a function returning arrays is illegal and not defining a pointer to function returning arrays. Prove me wrong if you can. Also if I'm wrong I would be happy if you explain me why is this sentence in the standard then?
Although clang doesn't seems to think that way and will rise an error in the above code stating that 'function cannot return array type 'int [4]''. But is this really a function (and not rather a pointer to one)?
EDIT:
OK - I was answered by citation of the standard paper that 'function declarators' can't have a return-type of array. However if we use a typedef name instead to declare a pointer to function returning arrays - would this be legal? -
typedef int arr_t[4];
arr_t (*pf1)(void);
Although I personally think that this case is also covered by the answers because the type-name defined by a 'typedef' is the same as one explicitly defined.
The sentence that you found is indeed only about function definitions, not about declarations. However, you missed another constraint:
6.7.5.3 Function declarators (including prototypes)
Constraints
1 A function declarator shall not specify a return type that is a function type or an array type.
Also if I'm wrong I would be happy if you explain me why is this sentence in the standard then?
There needs to be an additional requirement that a called function returns a complete object type because a function declaration is allowed to declare it as returning an incomplete type:
struct S;
struct S f(); /* valid */
void g() { f(); } /* invalid */
struct S { int i; };
void h() { f(); } /* valid */
It's not about arrays. The wording about "other than an array type" is just to make sure arrays don't accidentally become allowed by a mistake in the wording.
Declaring pointers to function returning arrays is actually legal?
No. Its not legal. You will get a compile time error. A function can't return an array.
For the time being, if int (*pf1)()[4]; is valid anyhow, then the function call
pf1();
doesn't make any sense. pf1 is not pointing to any function.

error: conflicting types for ‘six’ with gcc

Receiving error: conflicting types for ‘six’ when attempting to compile.
void main(){
const int k = 4;
six(&k);
}
float * six(const int *x)
{
float *p = malloc(sizeof(float));
*p = (float)*x;
return p;
}
Here is what is going on.
When the compiler does not encounter a prototype for a function before a call to it, it deduces the prototype from the call itself, and assumes the return type to be int. This is what it does in your example.
Later it finds the definition of the function, and it finds that the return type is actually float, which does not match with the prototype it has deduced earlier. Hence the error of conflicting types (instead of, say, missing prototype).
The solution is to, of course, provide a prototype for the function before a call to it is made.
You didn't declare six to the compiler before you called it, so the compiler was forced to guess what the signature of six is (typically, this is something like int func()). When it saw the actual declaration, it threw an error because the actual function declaration didn't match its implicit declaration.
You need to declare functions before they are used; place a declaration like
float *six(const int *x);
before main.
Solution to your problem
Just add the following declaration before main():
float *six(const int *x);
Or put your float *six(const int *x) definition before the main() function.
Why the compiler complain conflicting types
Since there is no declaration of your six() function before the compiler compile the main function, it will deduce the prototype from the function callsite, and will assume the return type to be int. And when it compiles your six() function, the compiler will find two function with the same name but different return type, so it complain the conflicting types error.
Thanks to Ziffusion's comment.
why to adjust your code in the above way
You should declare/define each of your element before use in C.
For your currently code, you need to declare your function type before the main function, so that the compiler knows what six() is when compile the main function.
Why there should be a declaration before use in C
For variables and other data types, since C is strong typed. When the variable is used, it need to be declared first, so that the compiler knows what type the variable is, and could do data type check.
For functions, since the C compiler compiles the code function by function, and will generate a function call statement in the assembly, so the compiler need to know the function parameter and return value data type, so that it could generated correct instructions to do parameter passing, and return value restoring. Normally, the compiler will compile the function in a source code file one by one from the start of the file to the end of the file, so you need to declare the function type before use it.

Strange typedef to function pointer

I am using a code written by somebody else, where they intend to use a function pointer. They do a very strange typdef that I can not understand. Below the code
typedef void (myType)(void);
typedef myType *myTypePtr;
I can understand that the main idea with myTypePtr is to create a "pointer to a function that receives void and returns void. But what about the original myType? What is that? a function type? Is not clear to me.
Furthermore, later there is this function prototype
int createData(int id,int *initInfo, myTypePtr startAddress)
However I get the compile error "expected declaration specifiers or '...' before 'myTypePtr' any idea why this is happening?. Thank you very much.
This first typedef
typedef void (myType)(void);
provides myType as a synonym for the type void (void), the type of a function that takes no arguments and returns void. The parentheses around myType aren't actually necessary here; you could also write
typedef void myType(void);
to make it clearer that it's the type of a function that takes void and returns void. Note that you can't actually declare any variables of function type; the only way to get an object of function type in C is to define an actual function.
The second typedef
typedef myType *myTypePtr;
then says that myTypePtr has a type that's equal to a pointer to a myType, which means that it's a pointer to a function that takes no arguments and returns void. This new type is equivalent to the type void (*)(void), but is done a bit indirectly.
As for your second error, I can't say for certain what's up without more context. Please post a minimal test case so that we can see what's causing the error.
Hope this helps!

How do I quiet the C compiler about a function pointer takes any number of arguments?

I have a function pointer inside a struct that gets dynamically set at runtime to the address of another function in various places in my code. It is defined in my header file like this:
void *(*run)();
During compile time, I get the following warning about this:
warning: function declaration isn't a prototype
This warning is benign, because the pointer is used in many places in my code to call the function it points to, and everything works just fine. However, I would really like to silence the warning.
If I change it to this:
void *(*run)(void);
I get compile errors whever I use it, because the various functions that make use of the pointer have different numbers of arguments, and saying void inside the parenthesies tells the compiler it accepts no arguments.
I can't use a va_list or anything fancy like that, as this is simply a pointer to another function, and I use a single pointer for them all because it keeps the code clean and simple.
I can silence the warning with adding this to my compiler flags:
-Wno-strict-prototypes
But I'd rather not have to disable compiler warnings with flags if I can avoid it.
So my question is: How do I notate this function pointer in the code in such a way that the compiler is satisfied with the fact that it accepts any number of any kind of arguments?
The code works perfectly. I just want the warning to go away.
Store the pointer as a void * and cast to the appropriate function pointer type when necessary? Keep in mind that it isn't necessarily safe to call one type of function pointer as if it were another type, so the warning you're starting out with isn't entirely invalid.
You can cast a function pointer like so:
void *genericPointer = ...;
void (*fp)(int, int) = genericPointer;
fp(123, 456);
Note that:
There's no explicit casting necessary here, as void * can always be cast to any pointer type.
The initial "void" before (*fp) is the return type of the function pointer.
You are trying to do things clean - i.e. involve the compiler in checks, but the design you invented simply cannot be clean by its principle. You cannot involve compiler in prototype checks this way, because you always must know, which parameters to pass at this particular case in runtime. Compiler cannot check this and if you make a mistake, segmentation fault is on the way.
But if I remember well, something like this was maybe used also in linux kernel (?). The solution is to have a general pointer (like the one you have) and each time you call a particular function you just typecast it to the pointer to function with the particular arguments. You may need to typecast it to void * first to silence the compiler again :-)
In C, when you call a function without a prototype visible, default argument promotions are applied to all of the arguments that you pass to the function. This means that the types that you actually pass do not necessarily match the types received by the function.
E.g.
void (*g)();
void f()
{
float x = 0.5;
g(x); // double passed
}
This means that you need to know that the function that you are actually calling has a compatible signature to that implied by the arguments that you are passing after promotion.
Given that you need to know this in any case you must know the function signature of the actual function being called at the call site which is using the function pointer. With this knowledge it is usually simpler and cleaner to use a function pointer with the correct prototype and you can avoid default argument promotion entirely.
Note that as you are defining your functions with prototypes, when you assigned a pointer to your function to a function pointer without a prototype you effective converted, say, a void(*)(int, int) to a void(*)() so it is completely correct and desirable to perform the reverse conversion before calling the function. gcc allows both these conversions without emitting any warnings.
E.g.
void PerformCall( void(*p)() )
{
if (some_condition)
{
// due to extra knowledge I now know p takes two int arguments
// so use a function pointer with the correct prototype.
void(*prototyped_p)(int, int) = p;
prototyped_p( 3, 4 );
}
}
Try typedefing the function pointer declaration and then have the caller explicityly cast it:
typedef void *(*run)();
//when calling...
void my_foo() {}
run r = (run)my_foo;
If the different function signatures are known, use a union. Otherwise, use a pointer of type void (*)(void) (actually, any function pointer type would do) to hold the generic pointer and convert to the proper type when setting the value and calling the code.
Example using a union:
union run_fn
{
void *(*as_unary)(int);
void *(*as_binary)(int, int);
};
struct foo
{
union run_fn run;
};
void *bar(int, int);
struct foo foo;
foo.run.as_binary = bar;
void *baz = foo.run.as_binary(42, -1);
Example using explicit casts:
struct foo
{
void (*run)(void);
};
void *bar(int, int);
struct foo foo;
foo.run = (void *(*)(int, int))bar;
void *baz = ((void *(*)(int, int))foo.run)(42, -1);
Don't use a void * to hold function pointers - such a conversion is unspecified by the ISO C standard and may be unavailable on certain architectures.
Ignoring the warning and using your code as-is is actually also a possibility, but keep in mind that any function argument will be subject to the default argument promotions and it's your responsibility that the promoted arguments properly match the declared parameters.

Resources