In some C project, I have seen this code:
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud;
(void)osize;
/* some code not using `ud` or `osize` */
return ptr;
}
Do the two casts to void serve any purpose?
It is there to avoid warnings from the compiler because some parameters are unused.
The reason for having unused parameters in the prototype is usually because the function needs to conform to some external API - perhaps it is a library function, or a pointer to that function is passed to another function that expects this calling convention. However not all arguments used by the calling convention are actually needed in the function itself.
The reason for mentioning the parameter name in the body is to avoid warnings like
unused.c: In function ‘l_alloc’:
unused.c:3:22: warning: unused parameter ‘ud’ [-Wunused-parameter]
void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
^~
This warning can be suppressed with using the actual parameter in the function body. For example if you do have the following statement:
ud;
This warning is now suppressed. However now GCC will produce another warning:
unused.c:5:5: warning: statement with no effect [-Wunused-value]
ud;
^~
This warning tells that the statement ud;, while being syntactically valid C, does not affect anything at all, and is possibly a mistake, not unlike the statement
abort;
which should perhaps have been written as abort(); instead for it to do something.
And that's where the (void) cast comes in - it will tell the compiler unambiguously and explicitly that the statement is supposed to have absolutely no effect at all.
Related
While perusing some STM32 middleware code, I came across this very odd line and can't parse it. It's basically,
(void)(foo);
It's not a void pointer cast - that would be straightforward. It's not calling a function and casting its return value as void - that would require a couple more parentheses. It looks like an rvalue without an lvalue. Is this just a no-op to prevent the function from being optimized away? Or does it actually do anything?
Here it is in context.
// SVCCTL_EvtAckStatus_t is just an enum typedef
typedef SVCCTL_EvtAckStatus_t (*SVC_CTL_p_EvtHandler_t)(void *p_evt);
void SVCCTL_RegisterCltHandler( SVC_CTL_p_EvtHandler_t pfBLE_SVC_Client_Event_Handler )
{
#if (BLE_CFG_CLT_MAX_NBR_CB > 0)
// Ignore all this
SVCCTL_CltHandler.SVCCTL_CltHandlerTable[SVCCTL_CltHandler.NbreOfRegisteredHandler] = pfBLE_SVC_Client_Event_Handler;
SVCCTL_CltHandler.NbreOfRegisteredHandler++;
#else
// This is the weird stuff
(void)(pfBLE_SVC_Client_Event_Handler);
#endif
return;
}
It doesn't do anything, except one thing. Stopping the compiler from complaining about unused variables. It is actually being recommended here, on SO, as a portable way of doing it: Portable UNUSED parameter macro used on function signature for C and C++
Example:
int somefunction(int a, int b, int c)
{
(void)(c); // c is reserved for future usage,
//stop the compiler from issuing "unused parameter" warning
return a+b;
}
What this does:
(void)(foo);
Is cast the expression foo to type void. It's a way of saying that an expression is explicitly not being used.
If you look at the definition of the function SVCCTL_RegisterCltHandler, you'll see that it takes a parameter named pfBLE_SVC_Client_Event_Handler. This parameter is used in the #if preprocessor block. If the #if condition is false, this parameter would otherwise be unused and the compiler would emit a warning that the parameter pfBLE_SVC_Client_Event_Handler is unused.
By casting this parameter to void in the #else block it uses the value and silences the compiler warning.
It's to prevent the compiler from complaining about foo being unused. That's literally it. It's like the maybe_unused attribute in C++.
#include <stdio.h>
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
p is a constant pointer to a variable x and can't point to other variables. But why don't we get error here and the output is 11 11?
This code doesn't violate a constraint, so the only thing you could expect from a compiler is a warning, which e.g. gcc gives you:
constptr.c: In function ‘main’:
constptr.c:6:9: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
foo(&p);
^
constptr.c: At top level:
constptr.c:9:10: warning: conflicting types for ‘foo’
void foo(int **p)
^
constptr.c:6:9: note: previous implicit declaration of ‘foo’ was here
foo(&p);
^
If you have a close look at these warnings, you see it's about an implicit declaration: foo() doesn't have a prototype before it is used, this isn't allowed by newer C standards, but compilers still support it for backwards compatibility. In that case, the compiler assumes the prototype is int foo(int). That's the reason for the next warning (conflicting types for foo).
If you correctly introduce a prototype like this:
#include <stdio.h>
void foo(int **p);
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
You get the warning one would expect:
constptr.c: In function ‘main’:
constptr.c:7:13: warning: passing argument 1 of ‘foo’ discards ‘const’ qualifier from pointer target type
foo(&p);
^
constptr.c:2:10: note: expected ‘int **’ but argument is of type ‘int * const*’
void foo(int **p);
^
So now the compiler warns you about the conversion dropping the const. C doesn't force you to write correct code, but you should anyways -- the warning tells you your code is incorrect and might invoke undefined behavior (as is the case here).
Although not related to your question, your code contains an even nastier case of undefined behavior: your last line in main() (the printf() line) dereferences a pointer that now points to an object of automatic storage duration (aka: the local variable j) that has gone out of scope and therefore doesn't exist any more!. It's unlikely that your compiler can warn you about this, still it's a recipe for desaster. So, always be very careful when writing C code.
Adding a very generic piece of advice here: Questions like this are often asked by people used to "modern" programming languages that are completely defined (e.g. Java, C#, and a lot more): Your code is either correct (and defined) or wrong and if it is wrong, you get either compilation errors or runtime exceptions. That's not how C works! In C, any code that adheres to the C grammar and doesn't violate a language constraint can be compiled and a lot of errors just lead to undefined behavior (which means anything could happen when executing that code). This means C "trusts" the programmer to do the correct thing -- the advantage is the possibility to create quite efficient native machine language code from a C source file, the downside is you're responsible yourself to make sure your code is actually correct. A best practice to start with is to always enable any warnings your C compiler gives you (a good setting for gcc would be e.g. -std=c11 -Wall -Wextra -pedantic) and always fix any warnings that come up.
Apart from the "modifying something const"-thing, the code as-is should actually compile with errors or warnings as the call of foo without having "forward-declared" it lets the compiler assume a different prototype (i.e. int foo(int)) than the actual definition then provides (i.e. int foo(int**); this could lead to "conflicting types for foo" - warning/error or something similar).
After having fixed this, with the following code, you should at least get a compiler warning (if not, turn on warnings or get a better compiler):
void foo3(int **p);
int main()
{
int i = 10;
int *const p = &i;
foo3(&p); // passing int * const * to parameter of type int ** discards const qualifiers
printf("%d\n", *p);
}
void foo3(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
Thereby you get undefined behaviour because of modifying a constant value (even if the compiler does not give you an "error").
BTW: accessing a pointer that points to a (local) object which's lifetime has ended (as you do with *p = &j and the printf in main) is undefined behaviour.
In some C project, I have seen this code:
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud;
(void)osize;
/* some code not using `ud` or `osize` */
return ptr;
}
Do the two casts to void serve any purpose?
It is there to avoid warnings from the compiler because some parameters are unused.
The reason for having unused parameters in the prototype is usually because the function needs to conform to some external API - perhaps it is a library function, or a pointer to that function is passed to another function that expects this calling convention. However not all arguments used by the calling convention are actually needed in the function itself.
The reason for mentioning the parameter name in the body is to avoid warnings like
unused.c: In function ‘l_alloc’:
unused.c:3:22: warning: unused parameter ‘ud’ [-Wunused-parameter]
void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
^~
This warning can be suppressed with using the actual parameter in the function body. For example if you do have the following statement:
ud;
This warning is now suppressed. However now GCC will produce another warning:
unused.c:5:5: warning: statement with no effect [-Wunused-value]
ud;
^~
This warning tells that the statement ud;, while being syntactically valid C, does not affect anything at all, and is possibly a mistake, not unlike the statement
abort;
which should perhaps have been written as abort(); instead for it to do something.
And that's where the (void) cast comes in - it will tell the compiler unambiguously and explicitly that the statement is supposed to have absolutely no effect at all.
static void llist_dtor(void *user, void *element)
{
(void)user;
(void)element;
/* Do nothing */
}
Is it no-operation function? Then why is casting done? Is it ok to pass NULL as one of its parameters?
That's indeed a no-op. The casts to (void) are here to avoid getting "parameter never used" warnings with some compilers (the casts are optimized away, but the parameters are still considered as "used").
You can pass NULL since the parameters are ignored anyway.
Yes, this is a no-op function.
The casting is a common trick to prevent the compiler complaining about unused parameters.
Yes, this is a no-op function and void casted lines are placed to avoid the "unused parameter" warning. For gcc, search for "unused" in the page: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
However, if it were C++ instead of C, I would probably write it little differently as
static void llist_dtor( void * /* user */, void * /* element */ )
{
/* Do nothing */
}
Note that the variable names are commented out.
That is not no-op. Like that you tell the compiler to ignore those two arguments.
For the following C code (for swapping two numbers) I am getting the "conflicting types" error for swap function:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a,b;
printf("enter the numbers to be swapped");
scanf("%d%d",&a,&b);
printf("before swap");
printf("a=%d,b=%d",a,b);
swap(&a,&b,sizeof(int));
printf("after swap");
printf("a=%d,b=%d",a,b);
getch();
}
void swap(void *p1,void *p2,int size)
{
char buffer[size];
memcpy(buffer,p1,size);
memcpy(p1,p2,size);
memcpy(p2,buffer,size);
return(0);
}
Compiler diagnostics:
<source>:10:6: warning: implicit declaration of function 'swap' [-Wimplicit-function-declaration]
swap(&a,&b,sizeof(int));
^~~~
program:15:6: warning: conflicting types for 'swap'
void swap(void *p1,void *p2,int size)
^~~~
Can anybody tell why that error is coming?
What is the solution for that?
The problem is that swap was not declared before it is used. Thus it is assigned a "default signature", one which will in this case not match its actual signature. Quote Andrey T:
The arguments are passed through a set
of strictly defined conversions. int *
pointers will be passed as int *
pointers, for example. In other words,
the parameter types are temporarily
"deduced" from argument types. Only
the return type is assumed to be int.
Aside from that, your code produces a bunch of other warnings. If using gcc, compile with -Wall -pedantic (or even with -Wextra), and be sure to fix each warning before continuing to program additional functionality. Also, you may want to tell the compiler whether you are writing ANSI C (-ansi) or C99 (-std=c99).
Some remarks:
Put spaces after commas.
Make main return an int.
And make it return 0 or return EXIT_SUCCESS.
Import the definition of getch: #include <curses.h>.
Or just use getchar.
Import the definition of memcpy: #include <string.h>.
Don't return something in a void function.
You may want to use malloc to allocate a buffer of variable size. That will also work with older compilers:
void swap(void *p1, void *p2, int size) {
void *buffer = malloc(size);
memcpy(buffer, p1, size);
memcpy(p1, p2, size);
memcpy(p2, buffer, size);
free(buffer);
}
You need to declare swap before using it. For example, put swap above main, or add a prototype for swap like this:
void swap(void *,void *,int);
int main ()
Incidentally main should be int not void and usually it returns the value zero, unless there is an error.
First off, the actual error message wouldn't hurt.
Secondly, making buffer of [size] only works on some compilers (that's a new feature, not all compilers have it yet). Are you sure yours does?
Thirdly, you need to declare swap before calling it. Add a prototype at the top of the file:
void swap(void *p1,void *p2,int size);
You failed to declare your swap explicitly, forcing the compiler to make assumptions about the function at the point of the call. The compiler, in accordance with C rules, will assume that swap is
int swap(int *, int *, size_t)
Later you declare your swap as
void swap(void *, void *, int)
which is obviously different from what the compiler assumed. This is the conflict the compiler is telling you about.
Also, your void swap attempts to return 0. What were you trying to achieve by that?
P.S. It's int main, not void main.
P.P.S. The program is not guaranteed to produce any output if its output does not end in a new-line character.
You may wonder why the program compiles at all without a prototype for swap(), and that's because the compiler is more than a C99 tool. It also compiles C89 and K&R C programs.
C89 added the prototypes. Prior to C89, the compiler didn't need to see the declaration (the prototype) of a function unless it returned something other than int and the types of the formal parameters were not known to the compiler at all. The compiler just called every function with the types of the actual arguments, which received a set of default argument promotions to simplify things. The programmer would run the lint utility to cross-check actual and formal parameters. This program is still shipped with the BSD distributions.
K&R programs and their corresponding code styles are still accepted by your compiler, so when it sees a function for which no prototype is available it just goes ahead and calls it anyway.
In this case, you switch paradigms in between the call and the definition of the function. The K&R C assumptions the compiler made about the undeclared function when it had to generate a call turned out not to be valid. Even if you had written the whole program in the K&R style the compiler would have made the same complaints when it found out the real types of the function arguments.
With GCC, this is a warning,
when you dont declare a function before using it, the compiler tries to guess the declaration using the type of call made to that function.Hence the behavior.
Well, it compiles on http://codepad.org (after removing the getch(), which is irrelevant). Maybe your compiler complains about using memcpy on non-restricted pointers?
In swap() p1 and p2 are not guaranteed not to be aliases. This is an actual bug waiting to happen - calling swap on &a[i] and &a[j] might blow up memcpy when i==j. Either use memmove (which is guaranteed not to blow up on overlapped areas) or declare the pointers restricted.