Consider the following main():
int main(int argc, char *argv[])
{
return (0);
}
Upon compilation with cc -Wall -Wextra, warnings saying "unused parameter" get generated.
When I do not need to use a parameter in a function (for instance in a signal handler function that makes no use of its int parameter), I am used to doing the following:
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
return (0);
}
(For that particular main(), I sometimes see other people do: argv = argv - argc + argc)
But what does (void)var actually do?
I understand that (void) is a cast, so I guess I am casting away the variable? What does the var; line (without the cast) do? Is it an empty assignment, an empty expression?
I would like to understand what is actually going on.
It's just a way of creating a 'harmless' reference to the variable. The compiler doesn't complain about an unused variable, because you did reference the value, and it doesn't complain that you didn't do anything with the value of the expression var because you explicitly cast it to void (nothing), indicating that you didn't care about the value.
I haven't seen this usage on variables before (because the compiler I use doesn't normally complain about unused function arguments,) but I see this used frequently to indicate to the compiler that you don't really care about the return value of a function. printf(), for example, returns a value, but 99% of C programmers don't know (or care) what it returns. To make some fussy compilers or lint tools not complain about an unused return value, you can cast the return value to void, to indicate that you know it's there, and you explicitly don't care about it.
Other than communicating your intent (that you don't care about this value) to the compiler, it doesn't actually do anything - it's just a hint to the compiler.
(void)argc;
(void)argv;
If a function argument is not used, like in your program, then this is the idiomatic way of suppressing the warning of unused function argument issued by some compilers. Any decent compiler will not generate code with these statements.
It evaluates the argument but does nothing with it which has the effect for most compilers to not issue a warning. The (void) cast is used so the compiler would not produce another warning notifying that the value is not used.
Another popular way to suppress the warning is to do:
variable = variable;
Note that I know some compilers that will issue another warning in presence of:
(void) arg;
like "statement with no effect".
As other persons correctly noted, It just suppresses a compiler warning about unused variable in your code.
Btw, Win32 has defined UNREFERENCED_PARAMETER macro to reach this goal.
My suggestion to make something like that in your code:
#ifdef _WIN32
# define UNUSED(x) UNREFERENCED_PARAMETER(x)
#else
# define UNUSED(x) (void) x
#endif
This may increase the code efficiency because the call of function dont need to load the registers for arguments.
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++.
I started programming with following definition of main()
void main(){}
Then somebody told me that this format of main() is bad programming because it should return int. He also told me that following definitions of main() are valid in C.
int main(void){}
or
int main(int argc,int *argv[]){}
Today I tried to experiment with other data types and surprisingly all the following compiles without errors.
char main(){}
float main(){}
int* main(){}
and even this compiles successfully
struct Abc{
int a;
};
struct Abc* main(){}
So my questions regarding this are following:
How does the OS deal with these unexpected return types? [I am asking this because I think return value of main() is used by OS]
Why is main() allowed to return any type?
Why do compiler designers make this so flexible by saying "main() should return int" I think there would be no problem if they said "main() must return int"?
If the return type of main is not either int or some implementation-defined type (where "implementation-defined" means that it's documented by the implementation), the behavior is undefined.
That means that a compiler is not required to issue a warning or error message, but the C standard says nothing about how the program behaves.
The actual behavior depends on the compiler (calling conventions, etc.) and on the operating system.
In many cases, the value returned by main (if any) will simply be interpreted as if it were an int. If it returns a double with the value 1.0, it might be equivalent to returning an int value 1065353216.
Or the compiler might reject it at compile time. Or your program might crash. As far as the C standard is concerned, literally anything can happen.
There are a lot of coding errors in C that compilers are not required to detect or to handle in any particular way. In such cases, it's entirely up to the programmer to get things right.
Just use the correct declaration. For hosted implementations, use either
int main(void) { /* ... */ }
or
int main(int argc, char *argv[]) { /* ... */ }
(For freestanding (embedded) implementations, the declaration is entirely implementation-defined, and the entry point may or may not be called main; consult your compiler's documentation.)
As for why declaring main incorrectly doesn't require a diagnostic, I'm not entirely sure. It does make things slightly simpler for compiler writers. They can treat main just like any other function. There are some non-standard forms that are actually useful; for example, UNIX-like systems sometimes permit
int main(int argc, char *argv[], char *envp) { /* ... */ }
where the third argument provides access to environment variables. I personally would prefer it if incorrect definitions of main had to be diagnosed.
This is also discussed in the comp.lang.c FAQ, starting at question 11.12a.
The OS expects return value of type int and gets it from the default place (e.g. register EAX). If you return other type, the OS will get value of EAX again. Nothing special.
In this code:
int main(int a, int b)
{
printf(" main(int, int) works \n\n");
return 0;
}
the signature of main is main(int, int), and it compiles successfully. Why?
Because the C standard doesn't prohibit non-standard signatures for main (see e.g. section 5.1.2 of the C99 standard).
However, you'll find that if you compile under GCC with the -Wall flag,1 it will complain:
test.c:4: warning: second argument of 'main' should be 'char **'
It assumes that you want to interact with a standard environment (i.e. process command-line parameters and return an exit status), in which case you must use int main(int, char **) or int main(void). If you use anything else, the contents of the arguments will be undefined.
1. I really wish ideone.com would allow you to specify compiler flags!
The C standard specifically prohibits the implementation from providing a prototype for main (C99, ยง5.1.2.2.1/1: "The function called at program startup is named main. The implementation declares no prototype for this function."), and a mismatch from the prototype is what would (normally) stop the code from compiling.
Without a prototype, you're back to programming like in the bad old days, when it was up to you to ensure that the arguments you passed to a function matched what it expected. Thankfully in the case of main, the signature is so well known that it's rarely a problem though.
Edit: note that if you want to badly enough, it's actually even possible to make use of the version with two int parameters (though the technique is prohibited in C++). main can call itself recursively, and in such a case can/could pass two int parameters:
int main(int a, int b) {
if (a == 2)
main(2, 10);
printf("%d, %d", a, b);
return 0;
}
This is pretty useless as it stands, but gives the general idea -- you're expected to run the program with no command line arguments, in which case a (which will receive what you normally call argc) will normally be 1 (i.e., the only argument it's trying to pass is the name of the program in argv[0]). In this case, it calls itself with some other values. When that happens, it prints out those values.
To be fair, I should add that that's pretty close to purely theoretical, and certainly not recommended. It'll work with most typical implementations, but the standard doesn't guarantee it. It's a silly, roundabout way to accomplishing what it does -- but at least with most typical compilers, it is (just barely) possible anyway.
There is no header file that specifies the signature of main, so no error will be reported. The compiler usually checks the return value only, for the case of main (the warnings of the signature of main is compiler dependent).
int main(int a, int b)
this is meaningless as the arguments passed to the main function are always
int main(int argc,char *argv[])
main is an unusual function.It is called by the operating system, and as C++ can run on many systems and the C++ standards cannot dictate to OS writers what data they pass to programs running on that OS - you can write any parameters you like in the main functions and the compiler will accept it.
please take a look at my codes below
#include <stdio.h>
void printOut()
{
static int i = 0;
if (i < 10)
{
printOut(i);
}
}
int main(int argc, char *argv[])
{
return 0;
}
i guess there should be an error due to my invoking the non-existed function prototype.Actually, the code compiles well with mingw5 compiler, which is weird for me, then i change to Borland Compiler, i get a warning message said that no printOut function prototype, is this only a warning ? What is more, the code executes well without any pop-up error windows.
In C, a function without any parameters can still take parameters.
That's why it compiles. The way to specify that it doesn't take any parameters is:
void printOut(void)
This is the proper way to do, but is less common especially for those from a C++ background.
Your program's behavior is undefined, because you define printOut() with no parameters, but you call it with one argument. You need to fix it. But you've written it in such a way that the compiler isn't required to diagnose the problem. (gcc, for example, doesn't warn about the parameter mismatch, even with -std=c99 -pedantic -Wall -Wextra -O3.)
The reasons for this are historical.
Pre-ANSI C (prior to 1989) didn't have prototypes; function declarations could not specify the expected type or number of arguments. Function definition, on the other hand, specified the function's parameters, but not in a way that the compiler could use to diagnose mismatched calls. For example, a function with one int parameter might be declared (say, in a header file) like this:
int plus_one();
and defined (say, in the corresponding .c file) like this:
int plus_one(n)
int n;
{
return n + 1;
}
The parameter information was buried inside the definition.
ANSI C added prototypes, so the above could written like this:
int plus_one(int n);
int plus_one(int n)
{
return n + 1;
}
But the language continued to support the old-style declarations and definitions, so as not to break existing code. Even the upcoming C201X standard still permits pre-ANSI function declarations and definitions, though they've been obsolescent for 22 years now.
In your definition:
void printOut()
{
...
}
you're using an old-style function definition. It says that printOut has no parameters -- but it doesn't let the compiler warn you if you call it incorrectly. Inside your function you call it with one argument. The behavior of this call is undefined. It could quietly ignore the extraneous argument -- or it could conceivably corrupt the stack and cause your program to die horribly. (The latter is unlikely; for historical reasons, most C calling conventions are tolerant of such errors.)
If you want your printOut() function to have no parameters and you want the compiler to complain if you call it incorrectly, define it as:
void printOut(void)
{
...
}
This is the one and only correct way to write it in C.
Of course if you simply make this change in your program and then add a call to printOut() in main(), you'll have an infinite recursive loop on your hands. You probably want printOUt() to take an int argument:
void printOut(int n)
{
...
}
As it happens, C++ has different rules. C++ was derived from C, but with less concern for backward compatibility. When Stroustrup added prototypes to C++, he dropped old-style declarations altogether. Since there was no need for a special-case void marker for parameterless functions, void printOut() in C++ says explicitly that printOut has no parameters, and a call with arguments is an error. C++ also permits void printOut(void) for compatibility with C, but that's probably not used very often (it's rarely useful to write code that's both valid C and valid C++.) C and C++ are two different languages; you should follow the rules for whichever language you're using.
I'm trying to check a C program with Splint (in strict mode). I annotated the source code with semantic comments to help Splint understand my program. Everything was fine, but I just can't get rid of a warning:
Statement has no effect (possible undected modification through call to unconstrained function my_function_pointer).
Statement has no visible effect --- no values are modified. It may modify something through a call to an unconstrained function. (Use -noeffectuncon to inhibit warning)
This is caused by a function call through a function pointer. I prefer not to use the no-effect-uncon flag, but rather write some more annotations to fix it up. So I decorated my typedef with the appropriate #modifies clause, but Splint seems to be completely ignoring it. The problem can be reduced to:
#include <stdio.h>
static void foo(int foobar)
/*#globals fileSystem#*/
/*#modifies fileSystem#*/
{
printf("foo: %d\n", foobar);
}
typedef void (*my_function_pointer_type)(int)
/*#globals fileSystem#*/
/*#modifies fileSystem#*/;
int main(/*#unused#*/ int argc, /*#unused#*/ char * argv[])
/*#globals fileSystem#*/
/*#modifies fileSystem#*/
{
my_function_pointer_type my_function_pointer = foo;
int foobar = 123;
printf("main: %d\n", foobar);
/* No warning */
/* foo(foobar); */
/* Warning: Statement has no effect */
my_function_pointer(foobar);
return(EXIT_SUCCESS);
}
I've read the manual, but there's not much information regarding function pointers and their semantic annotations, so I don't know whether I'm doing something wrong or this is some kind of bug (by the way, it's not already listed here: http://www.splint.org/bugs.html).
Has anyone managed to successfully check a program like this with Splint in strict mode? Please help me find the way to make Splint happy :)
Thanks in advance.
Update #1: splint-3.1.2 (windows version) yields the warning, while splint-3.1.1 (Linux x86 version) does not complain about it.
Update #2: Splint doesn't care whether the assignment and the call are short or long way:
/* assignment (short way) */
my_function_pointer_type my_function_pointer = foo;
/* assignment (long way) */
my_function_pointer_type my_function_pointer = &foo;
...
/* call (short way) */
my_function_pointer(foobar);
/* call (long way) */
(*my_function_pointer)(foobar);
Update #3: I'm not interested in inhibiting the warning. That's easy:
/*#-noeffectuncon#*/
my_function_pointer(foobar);
/*#=noeffectuncon#*/
What I'm looking for is the right way to express:
"this function pointer points to a function which #modifies stuff, so it does have side-effects"
Maybe you are confusing splint by relying on the implicit conversion from "function name" to "pointer to function" in your assignment of my_function_pointer. Instead, try the following:
// notice the &-character in front of foo
my_function_pointer_type my_function_pointer = &foo;
Now you have an explicit conversion and splint doesn't need to guess.
This is just speculation, though. I haven't tested it.
I'm not familiar with splint, but it looks to me that it will check function calls to see if they produce an effect, but it doesn't do analysis to see what a function pointer points to. Therefore, as far as it's concerned, a function pointer could be anything, and "anything" includes functions with no effect, and so you'll continue to get that warning on any use of a function pointer to call a function, unless you so something with the return value. The fact that there's not much on function pointers in the manual may mean they don't handle them properly.
Is there some sort of "trust me" annotation for an entire statement that you can use with function calls through pointers? It wouldn't be ideal, but it would allow you to get a clean run.
I believe the warning is correct. You're casting a value as a pointer but doing nothing with it.
A cast merely makes the value visible in a different manner; it doesn't change the value in any way. In this case you've told the compiler to view "foobar" as a pointer but since you're not doing anything with that view, the statement isn't doing anything (has no effect).