Function as parameter to function [duplicate] - c

This question already has answers here:
C Why function pointer as parameter instead of just a function?
(2 answers)
Closed 6 years ago.
I just noticed that this compiles without any errors or warnings using -pedantic -Wall with both gcc and clang.
#include <stdio.h>
int x = 0;
void func(int f(const char *)) {
f("func()!");
}
int main(void) {
func(puts);
}
It appears that the parameter f is treated like pointer to function int (*)(const char *) in this case.
But this a behavior that I have never seen or heard anything about. Is this legal C code? And if so then what happens when you have a function as a parameter to a function?

It is allowed by the standard. From C99 standard chapter 6.9.1 (took from http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf):
EXAMPLE 2 To pass one function to another, one might say
int f(void);
/*...*/
g(f);
Then the definition of g might read
void g(int (*funcp)(void))
{
/*...*/
(*funcp)(); /* or funcp(); ... */
}
or, equivalently,
void g(int func(void))
{
/*...*/
func(); /* or (*func)(); ... */
}

Related

The different statements cause the type conversion to be different. c/gcc [duplicate]

This question already has answers here:
Unspecified number of parameters in C functions - void foo()
(5 answers)
Closed 1 year ago.
If I add "double" into statement then it will print 60.00
else the code will print 0.0000..
#include <stdio.h>
int main(void)
{
void foo();// if i add "double" into statement then will printf 60.00
char c = 60;
foo(c);
return 0;
}
void foo(double d)
{
printf("%f\n", d);//now printf 0.0000
}
Yor code invokes Undefined Behaviour as the caller does not know the parameters of foo. Your prototype says that the function will take an unspecified number of parameters. It does not say anything about the types of those parameters. So it does the implicit conversion to int and passes int to foo.
foo expects the double parameter.
What to do?
Add the function prototype befoe the function call.
void foo(double);
int main(void)
{
char c = 60;
foo(c);
return 0;
}
void foo(double d)
{
printf("%f\n", d);//now printf 60.0000
}

why can not malloc in global but can use inline function for malloc [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 2 years ago.
Hi i have a test code for calling malloc as below:
#include <stdio.h>
#include <stdlib.h>
int *p;// = (int*)malloc(sizeof(int));
int main() {
//...
}
Of course this code will be fail when compile with the error: initializer element is not constant and i have referenced this question: Malloc function (dynamic memory allocation) resulting in an error when it is used globally. They said that we have to use malloc() in side a function. But if i change my code to:
#include <stdio.h>
#include <stdlib.h>
int *p;
static int inline test_inline(int *x) {
printf("in inline function \n");
x = (int*)malloc(sizeof(int));
return x;
}
test_inline(p);
int main(){
//...
}
As the definition of inline function: "Inline Function are those function whose definitions are small and be substituted at the place where its function call is happened. Function substitution is totally compiler choice." So this mean we can substitute the inline function test_inline in above example with the code inside it and it means we have call malloc() in global ? Question 1: is this wrong about inline or malloc() ?
Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
printf("hello");
}
test();
int main() {
//...
}
So this mean in the global we still can declaration and initialization and call function. But when we compile the above code it has a warning that warning: data definition has no type or storage class So why we have this warning with variable b ? I do not see any thing which inconsequential here. And with the line test(); i have call a function outside main(), i know this make no sense because we never run test() but i have no problem, stil build success. So back to question 1 about the malloc(), i think with the answer that "we can not call a function in global or can not initialize", i think it is not true. Is there any explain more reasonable?
Please refer to the comments.
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1; //this is only allowed, because the previous line is a tentative definition. [1]
int test() {
printf("hello");
}
test(); // this is taken as a function declaration, not a function call [2]
int main() {
//...
}
Case [1]:
Change you code to
int b = 5; // not a tentative defintion.
b = 1; // this assignment is not valid in file scope.
you'll see an error.
Case [2]:
If the signature of the function differs, you'll again see an error. Example: try the below:
float test( int x ) {
printf("hello");
return 0.5;
} //return changed to float, accepts an int as paramater.
test(); //defaults to int and no parameter - conflict!!
this will produce the error for conflicting types.
So, bottom line, no assignment, function call - all in all, no code that needs to execute at runtime, can be put into file scope. The reason behind that being, unless it's contained in a function that's called from main(), there's no way to know when / how to execute it.
You're not calling functions "globally".
Taking your example:
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
printf("hello");
}
test();
int main() {
//...
}
In C types default to int.
So the lines
int b;
b = 1;
are basically
int b;
int b = 1;
and the lines
int test() {
printf("hello");
}
test();
are just
int test() {
printf("hello");
}
int test(); // -> this is just a matching declaration
Have a look at:
https://godbolt.org/z/3UMQAr
(try changing int test() { ... to char test() { ... and you get a compiler error telling you that those types don't match)
That said, you can't call functions there. Functions are called at runtime by your program (especially malloc, which is asking your OS to allocate memory for you). I'm not a C expert here but as far as I know C doesn't have constexpr functions, which would be the only "exception".
See: Compile-Time Function Execution
Question 1: is this wrong about inline or malloc()
kind of: malloc does have to be called in a function, but the variable it works on can be declared global. i.e. int *pointer = NULL;//global scope
then pointer = malloc(someByteCount);//called within function. Now, pointer is still global, but also has a memory address pointing to someByteCount bytes of memory.
Question 2: In C, all functions are defined on the same level of a .c file, just like main(void){...return 0}, but all functions (except main(void)) must be called within the {...} of other functions, so in short, functions cannot be called from global space.
Illustration for Q2:
//prototypes
void func1(void);
void func2(void);
void func3(void);
int main(){
int val = test_inline(p);//...
}
int main(void)
{
//legal
func1();
func2();
func3();
return 0;
}
//not legal
func1();
func2();
func3();
//definitions
void func1(void)
{
return 0;
}
void func2(void)
{
return 0;
}
void func3(void)
{
return 0;
}
Errors in syntax of your example (see comments):
int *p = NULL;//initialize before use
static int inline test_inline(int *x) {
printf("in inline function \n");
x = (int*)malloc(sizeof(int));
printf("%p\n", x);
return 0;
//return x;//function returns int, not int *
}
//... test_inline(p);//must be called in a function
int main(void){
int val = test_inline(p);//function declaration returns int, not pointer
return 0;
}
This code compiles, and runs, but as noted in comments, usefulness may be lacking.
Question 1: is this wrong about inline or malloc() ?
Neither. Your understanding of inline is incorrect. The function call may be replaced with an inline expansion of the function definition. First, let's fix the function definition because the return type int doesn't match the type of what you're actually returning:
static inline int *test_inline( int *x )
{
printf( "in inline function\n" );
x = malloc( sizeof *x );
return x; // x has type int *, so the return type of the function needs to be int *
}
If you call this function like so:
int main( void )
{
int *foo = test_inline( foo );
...
}
what the compiler may do is substitute the function call with the assembly language equivalent of the following:
int main( void )
{
int *foo;
do
{
printf( "in inline function\n" );
int *x = malloc( sizeof *x );
foo = x;
} while( 0 );
...
}
Nothing's happening "globally" here. The substitution is at the point of execution (within the body of the main function), not at the point of definition.
Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:
In the code
int test() {
printf("hello");
}
test();
the line test(); is not a function call - it's a (redundant and unnecessary) declaration. It does not execute the function.
Here are some excerpts from the language definition to clarify some of this:
6.2.4 Storage durations of objects
...
3 An object whose identifier is declared without the storage-class specifier
_Thread_local, and either with external or internal linkage or with the storage-class
specifier static, has static storage duration. Its lifetime is the entire execution of the
program and its stored value is initialized only once, prior to program startup.
Bold added. Any variable declared outside the body of a function (such as p in your first code snippet) has static storage duration. Since such objects are initialized before runtime, they cannot be initialized with a runtime value (such as the result of a function call).
6.7.4 Function specifiers
...
6 A function declared with an inline function specifier is an inline function. Making a
function an inline function suggests that calls to the function be as fast as possible.138)
The extent to which such suggestions are effective is implementation-defined.139)
138) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline
substitution’’. Inline substitution is not textual substitution, nor does it create a new function.
Therefore, for example, the expansion of a macro used within the body of the function uses the
definition it had at the point the function body appears, and not where the function is called; and
identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a
single address, regardless of the number of inline definitions that occur in addition to the external
definition.
139) For example, an implementation might never perform inline substitution, or might only perform inline
substitutions to calls in the scope of an inline declaration
All this means is that the inlined code behaves like it was still a single function definition, even if it's expanded in multiple places throughout the program.

Why void* valid in C? [duplicate]

This question already has answers here:
What does void* mean and how to use it?
(10 answers)
Closed 4 years ago.
Why we can decalre a variable as "void* x" but not "void x"?
Why is "void* x" useful?
example:
int main()
{
void* a;
return 0;
}
The above code compiles and runs sucessfully
int main()
{
void a;
return 0;
}
The above code gets the following compile error:
b.c:6:10: error: variable has incomplete type 'void'
void a;
^
1 error generated.
I think it is because void is generally used as a return type for functions to indicate that there is no return value.
Void* is actually incredibly useful! Void* is used as a return type for memory functions like malloc() and calloc() because it allows them to manipulate any data type. Additionally, void* can be used to create generic functions. An often cited example of this is:
void qsort (void* base, size_t num, size_t size, int (*comparator)(const void*,const void*))
This is a generic function implementing quicksort. The comparison function in this case uses void* pointers to suggest it can compare any data type.

What does an empty parameter list mean? [duplicate]

This question already has answers here:
Why does a function with no parameters (compared to the actual function definition) compile?
(11 answers)
Closed 9 years ago.
The book that i am currently reading states that when you declare a function in c that accepts no arguments, but you do not use the keyword void "the function call can pass any
arguments it wants". so i attempted this.
int number();
int main(void)
{
int x =1;
printf("%d",number(x));
}
int number()
{
return x;
}
but it did not compile??? how does this work?
This is an obsolescent feature1 from before C was standardized, decades ago.
Never use it.
In ancient C, a decade before you were born, you could declare a function with no parameters. When you called it, the compiler would promote the arguments to default types and pass them to the function. Essentially, the compiler figured out the parameter declarations from the arguments in the call.
The function should still be defined with parameters, and they should match the way the function is called.
1 “Feature” is the wrong word. It was the way things were done at the time, since better ways were not yet widely developed. In a new programming language, this characteristic would be considered a deficiency.
In support of Eric Postpischil's answer I would like to quote from the C11 standard (6.11 Future language directions)
6.11.6 Function declarators
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
and
6.11.7 Function definitions
The use of function definitions with separate parameter identifier and
declaration lists (not prototype-format parameter type and identifier
declarators) is an obsolescent feature.
Emphasis is mine :)
The issue here is that your function number has no knowledge of x.
That is, when you have the function number return x, it doesn't have any x in scope to return, and so this is a compile error. If, instead, you wrote:
int number() {
return 5;
}
it would compile fine.
Well, if you want pass something to it without limit , you may need a a variable argument list.Here is an example:
#include <stdio.h>
#include <stdarg.h>
int number(int , ... );
int main(void)
{
int x =1;
printf("%d",number(1,x));
}
int number(int n, ... )
{
va_list ap;
va_start(ap,n);
int x = va_arg(ap,int);
va_end(ap);
return x;
}
Or , if you just want to pass x but not use it.
#include <stdio.h>
int number();
int main(void)
{
int x =1;
printf("%d",number(x));
}
int number()
{
int x = 1;
return x;
}
It can compile and work. When you declare int number (); in C , you mean this function can be given unspecial type . however , you can't use it.
Well I edited the whole answer after finding the answer.
What you want to do is number(void) not main(void). That's what you wanted and that will print any variable as a integer. If you pass the char "F" int number(void) will return the number 70, the int form of "F". In code:
int number(void e);
void main(){
char C = 'F';
printf("%d",number(C));
};
int number(void e){
return e;
};
Note:
You must always pass an argument if you want a variable that's out of scope.

ISO C Void * and Function Pointers

While following some tutorials and reading about function pointers I learned that evidently assigning a void pointer to a function pointer in ISO C is undefined, is there any way to resolve the warning I receive during compile time (e.g. a better way of coding it) or should I just ignore it?
Warning:
ISO C forbids assignment between function pointer and 'void *' [-pedantic]
Example Code:
void *(*funcPtr)();
funcPtr = GetPointer();
GetPointer is a function that returns a void pointer E.G.
void *GetPointer();
In tlpi-book I found this trick very interesting:
#include <dlfcn.h>
int
main(int argc, char *argv[])
{
...
void (*funcp)(void); /* Pointer to function with no arguments */
...
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
}
No. The compiler is right, and you too: in C89 and C99, you can't convert between data pointers (which void * is) and function pointers, so the only way for resolving the warning is returning a function pointer from the function.
(Note, however, that in practice this works despite the warning, and even there's this inconsistency in the standard library - the dlsym() function is used for obtaining function pointers, but it returns void * - so essentially you can ignore the warning. It will work, although strictly speaking the behavior is undefined here.)
I encountered this problem using glib. Glib data structures, such as GSList usually have a field called void *data. I wanted to store functions in a list and got a bunch of errors similar to this:
warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic]
This example generates a bunch of warnings using gcc -Wall -ansi -pedantic
typedef int (* func) (int);
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
func f;
functions = g_slist_append(functions, mult2);
f = (func *) functions->data;
printf("%d\n", f(10));
return 0;
}
So I wrapped the function in a struct and all the warnings go away:
struct funcstruct {
int (* func) (int);
};
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
struct funcstruct p;
p.func = mult2;
functions = g_slist_append(functions, &p);
p = * (struct funcstruct *) functions->data;
printf("%d\n", p.func(10));
return 0;
}
It's arguable that this is quite a bit of extra code to make a few warnings disappear, but I don't like my code to generate warnings. Also, the above are toy examples. In the real code I'm writing, it turns out to be quite useful to wrap the list of functions in a struct.
I'd be interested to hear if this is problematic or if there's a better way of doing it.

Resources