Why to put argc argv arguments in main when they never accessed? - c

I often see programs where people put argc and argv in main, but never make any use of these parameters.
int main(int argc, char *argv[]) {
// never touches any of the parameters
}
Should I do so too? What is the reason for that?

The arguments to the main function can be omitted if you do not need to use them. You can define main this way:
int main(void) {
// never touches any of the parameters
}
Or simply:
int main() {
// never touches any of the parameters
}
Regarding why some programmers do that, it could be to conform to local style guides, because they are used to it, or simply a side effect of their IDE's source template system.

When you have a function, it's obviously important that the arguments passed by the caller always match up properly with the arguments expected by the function.
When you define and call one of your own functions, you can pick whatever arguments make sense to you for the function to accept, and then it's your job to call your function with the arguments you've decided on.
When you call a function that somebody else defined — like a standard library function — somebody else picked the arguments that function would accept, and it's your job to pass them correctly. For example, if you call the standard library function strcpy, you just have to pass it a destination string, and a source string, in that order. If you think it would make sense to pass three arguments, like the destination string, and the size of the destination string, and the source string, it won't work. You don't get to make up the way you'll call the function, because it's already defined.
And then there are a few cases where somebody else is going to call a function that you defined, and the way they're going to call it is fixed, such that you don't have any choice in the way you define it. The best example of this (except it turns out it's not such a good example after all, as we'll see) is main(). It's your job to define this function. It's not a standard library function that somebody else is going to define. But, it is a function that somebody else — namely, the C start-up code — is going to call. That code was written a while ago, by somebody else, and you have no control over it. It's going to call your main function in a certain way. So you're constrained to write your main function in a way that's compatible with the way it's going to be called. You can put whatever you want in the body of your main function, but you don't get to pick your own arguments: there are supposed to be two of those, an int and a char **, in that order.
Now, it also turns out that there's a very special exception for main. Even though the caller is going to be calling it with those two predefined arguments, if you're not interested in them, and if you define main with no arguments, instead, like this:
int main()
{
/* ... */
}
your C implementation is required to set things up so that nothing will go wrong, no problems will be caused by the caller passing those two arguments that your main function doesn't accept.
So, in answer to your question, many programs are written to accept int argc and char **argv because they're complying with the simple rule: those are the arguments the caller is accepting, so those are the arguments they believe their main function should be defined as accepting, even if it doesn't actually use them.
Programmers who define main functions that accept argc and argv without using them either haven't heard of, or choose not to make use of, the special exception that says they don't have to. Personally, I don't blame them: that special exception for main is a strange one, which didn't always exist, so since it's not wrong to define main as taking two required arguments but not using them, that could be considered "better style".
(Yes, if you define a function that fails to actually use the arguments it defines, your compiler might warn you about this, but that's a separate question.)

Related

Why is argc given as a parameter to main when we do not actually pass it?

Why is argc is given as a parameter in C (i.e. int main(int argc, char **argv)) when we actually do not pass the count of our arguments?
I want to know why the syntax is written in such a way when argc does not take the parameter passed. Why didn't they design it as a keyword or a function like length when it is written only for us to know the count?
You're right that when one of the exec*() family of functions is called, you do not specify the number of arguments explicitly — that is indicated by the presence of a null pointer at the end of a list of arguments.
The count is passed to the int main(int argc, char **argv) function for convenience, so that the code does not have to step through the entire argument list to determine how many arguments are present. It is only convenience — since argv[argc] == 0 is guaranteed, you can determine the end of the arguments unambiguously.
For the rest, the reason is historical — it was done that way from the start, and there has been no reason to change it (and every reason not to change it).
It isn't clear what you mean by 'a keyword' for the argument count. C has very few keywords, and one for this purpose would be peculiar. Similarly, although there could be a function to do the job, that isn't really necessary — the interface chosen obviates the need for such a function. It might have been useful to have functional access to the argument list (and the environment) so that library code could enumerate the arguments and environment. (Using getenv(), you can find out about environment variables you know about; you can't find out about environment variables which you don't know about. On POSIX systems, there is the extern char **environ; variable that be used to enumerate the content of the environment, but that's not part of Standard C.)

How does c allow you to not pass all the parameters?

So I never realized this until I accidentally did it. The following is a method header i have:
void processI_TypeInstruction(char *I_TypeInstruction, char* currentLine,
FILE *outputFilePointer, VariableVector *labelVector);
one of my calls to this method looks like this:
processI_TypeInstruction("lw", line1, outputFile);
and all my tests pass and everything works. I was wondering what C does to make this functionality work??? Thanks.
You must not have the header file with the prototype for processI_TypeInstruction in the file with that call.
Function prototypes are not required in C. If a function does not have a prototype, the compiler makes no assumption about the number of parameters so it will allow you to pass any number of parameters in a function call. The is the behavior of the original language. Function prototypes were not added until the 1989 C standard.
The call works because the C calling convention has the caller clean up the stack. Since the caller knows how many parameters were passed, it can clean up all the parameters that it passed. Of course if the function tries to access a parameter then it will read into un-initialized stack space and who knows what will happen.
That should definitely be a compilation error in C, however, C++ does support function overloading (same function name, different number of arguments, different function signature)...

Calling C functions with too many arguments

I am currently changing the function signatures of a class of functions in an application. These functions are being stored in a function table, so I was expecting to change this function table as well. I have just realised that in certain instances, we already use the new function signature. But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
When the function is called, it will be passed extra parameters that are not really part of the function declaration, but they are on the end of the parameter list.
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
It evidently works just fine across multiple platforms but out of curiosity I'd like to know how and why it works.
But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
So the compiler gets to be no help to speak of. C programmers cast too much. >_<
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
Technically, you've got undefined behavior. But it's defined for your platform to use the standard C calling conventions (see Scott's answer), or something that maps directly to them (usually by mapping the first N parameters to a certain set of processor registers).
This comes up a lot with variable argument lists, too. For example, printf is declared something like:
int printf(const char* format, ...);
And its definition usually uses the stdarg system to handle the extra arguments, which looks like:
#include <stdarg.h>
int printf(const char* format, ...)
{
va_list ap;
int result;
va_start(ap, format);
result = vprintf(format, ap);
va_end(ap);
return result;
}
If you're on a platform with standard C calling conventions, that va_end(ap) macro usually turns into a do-nothing. In this case, you can get away with passing extra arguments to a function. But on some platforms, the va_end() call is required to restore the stack to a predictable state (i.e. where it was before the call to va_start); in those cases, your functions will not leave the stack the way it found it (it won't pop enough arguments back off the stack) so your calling function could, for example, crash on exit when it fetches a bogus value for a return address.
Your functions must certainly be using the cdecl calling convention (http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). This pushes arguments on the stack in reverse order, from right to left, ensuring that the last argument can be easily located (top of the stack) and used to interpret the remainder, such as a printf format string. It is also the responsibility of the caller to clean up the stack, which is a bit less compact than the function itself doing so (as in pascal/stdcall convention), but ensures that variable argument lists can be used, and implies that trailing arguments can be ignored.

Use of (apparently) empty C function

Can anyone comment on the point of the following function, which appears to do not very much:
// Returns stored values
int getDetails(const int param1[],
int* param2,
int* param3,
int* param4)
{
(void)param1;
(void)param2;
(void)param3;
(void)param4;
return 0;
}
The comment is actually there with the code. I'm thinking it must be some kind of odd stub but it is being called and I'm racking my brains to try to imagine what I'm missing.
My best hunch so far is that the function has been deprecated but not removed and the (void)param is to avoid compiler warnings about unused variables.
Statements like (void)param1; are typically used to suppress warnings about unused function parameters. (As an aside, in C++ you could also comment out or remove the parameter names.)
You're correct that the function does nothing. If other code doesn't create a pointer to it, you could safely remove it.
It's an empty function. Casts to void suppress warnings about unused parameters.
Such functions are often used when a function must be called unconditionally or a valid function pointer must be provided, but really the function has nothing to do.
I have a few such functions in my compiler's code generator. There are two code generators actually, one for x86 and the other for MIPS. I compile and link one or the other, never both at the same time.
The code generators are different internally but have the same external API. So, some functions specific to one CPU have some work to do while the same functions for the other have nothing to do. Logically, some of them are empty since there's nothing to do.
My guess (opinion - sorry!) that it could be a stub as you say. If you have a function that takes one or more function pointers to achieve something and it does not allow for a NULL (don't bother with this) then you have to provide something for it to call.
The casts are probably to avoid the "unused parameter" warning.
You're right, it has no point.
All it does is explicitly ignore the arguments by evaluating them and casting the result to (void), and return 0.
Is the return value being used in the context of the call? The best approach is of course to remove the call and replace it with a 0 if the return value is being used, and test the program.
Some Compilers shows error/warning when you are not using the arguments passed to it , to avoid that mention that like it in your code . If the function is not called any where or not assigned to any function pointers , you can remove it as it is not doing anything specific

Access command line arguments without using char **argv in main

Is there any way to access the command line arguments, without using the argument to main? I need to access it in another function, and I would prefer not passing it in.
I need a solution that only necessarily works on Mac OS and Linux with GCC.
I don't know how to do it on MacOS, but I suspect the trick I will describe here can be ported to MacOS with a bit of cross-reading.
On linux you can use the so called ".init_array" section of the ELF binary, to register a function which gets called during program initilization (before main() is called). This function has the same signature as the normal main() function, execept it returns "void".
Thus, you can use this function to remember or process argc, argv[] and evp[].
Here is some code you can use:
static void my_cool_main(int argc, char* argv[], char* envp[])
{
// your code goes here
}
__attribute__((section(".init_array"))) void (* p_my_cool_main)(int,char*[],char*[]) = &my_cool_main;
PS: This code can also be put in a library, so it should fit your case.
It even works, when your prgram is run with valgrind - valgrind does not fork a new process, and this results in /proc/self/cmdline showing the original valgrind command-line.
PPS: Keep in mind that during this very early program execution many subsystem are not yet fully initialized - I tried libc I/O routines, they seem to work, but don't rely on it - even gloval variables might not yet be constructed, etc...
In Linux, you can open /proc/self/cmdline (assuming that /proc is present) and parse manually (this is only required if you need argc/argv before main() - e.g. in a global constructor - as otherwise it's better to pass them via global vars).
More solutions are available here: http://blog.linuxgamepublishing.com/2009/10/12/argv-and-argc-and-just-how-to-get-them/
Yeah, it's gross and unportable, but if you are solving practical problems you may not care.
You can copy them into global variables if you want.
I do not think you should do it as the C runtime will prepare the arguments and pass it into the main via int argc, char **argv, do not attempt to manipulate the behaviour by hacking it up as it would largely be unportable or possibly undefined behaviour!! Stick to the rules and you will have portability...no other way of doing it other than breaking it...
You can. Most platforms provide global variables __argc and __argv. But again, I support zneak's comment.
P.S. Use boost::program_options to parse them. Please do not do it any other way in C++.
Is there some reason why passing a pointer to space that is already consumed is so bad? You won't be getting any real savings out of eliminating the argument to the function in question and you could set off an interesting display of fireworks. Skirting around main()'s call stack with creative hackery usually ends up in undefined behavior, or reliance on compiler specific behavior. Both are bad for functionality and portability respectively.
Keep in mind the arguments in question are pointers to arguments, they are going to consume space no matter what you do. The convenience of an index of them is as cheap as sizeof(int), I don't see any reason not to use it.
It sounds like you are optimizing rather aggressively and prematurely, or you are stuck with having to add features into code that you really don't want to mess with. In either case, doing things conventionally will save both time and trouble.

Resources