In glibc, main is documented as either,
int main (int argc, char *argv[])
Or,
int main (int argc, char *argv[], char *envp[])
Can you define all the arguments as being const if you don't want to change them?
int main (const int argc, const char * const argv[])
Is it supported, unsupported, or illegal?
In C, the implementation is allowed to support basically any type for the main function, so it may very well be that your particular implementation allows the various forms you have proposed. (And indeed it seems to allow the three-parameter version that exposes the environment.) However, the implementation is only required to accept the two forms
int main(void)
and
int main(int, char**)
Since int(int, const char**) isn't the same type as int(int, char**), your proposed "constified" version is not strictly speaking required to be supported and falls under the first rule. It is, however, quite likely to work since char* and const char* are laid out the same way as far as the ABI is concerned, and the data you're given is mutable anyway.
Note further that int f(int) and int f(const int) are the same identical prototype, so there is no problem here regarding top-level qualifications of the parameters.
Related
I was going through the difference in C and C++ and I found a tricky point. Can you please elaborate the below points:
In C, we can call main() Function through other Functions.
In C++, we cannot call main() Function through other functions.
How to call main() from another function and what is the use case of it?
#TrevorHickey hit the nail on the head (where did his answer go?) - C++ forbids calling main from within a different function (for good reason)... Not that any compiler is likely to stop you (I don't think most of them care).
An obvious workaround would be to move main's functionality into a container function and call it from there, as suggested by #KlasLindbäck.
i.e.
int my_application(int argc, char const * argv[]) {
// do stuff
return 0;
}
int main(int argc, char const * argv[]) {
return my_application(argc, argv);
}
Another "hack" that probably only works because compilers let you call main anyway (As also pointed out by #KlasLindbäck in the comments), would be to use function pointers. i.e.
int main(int argc, char const * argv[]) {
// do stuff
}
// shouldn't compile... but hey, you never know.
int (*prt_to_main)(int, char const* argv[]) = main;
void test_run(void) {
prt_to_main(0, NULL);
}
I'm a beginner with the langage C and i'd like to know what's the difference between this:
int main(int argc, const char * argv[])
and this:
int main(int argc, char * argv[])
I think it's the same thing but i'm not sure. Could someone explain me the difference.
Thank you
int main(int argc, char * argv[]) is correct and must be accepted by the compiler.
int main(int argc, const char * argv[]) may be rejected by the compiler. If the compiler accepts it then the behaviour is implementation-defined. This means that the compiler must document which non-standard signatures of main it accepts, and document the behaviour of each one.
So, consult your compiler's documentation to see what it says about parameters of main. A reasonable expectation would be that the compiler makes this form behave the same as if you had int main(int argc, char *__argv[]) { const char **argv = (const char **)__argv; .
I guess firstly you have to know const char* c; and char *const c;
In const char* c, const means you can't change the content c points to.
In char *const c, const means you can't change the position c points to.
As you know, the value stored in char* c is an address in memory, so the first const indicates that the value that c points to isn't supposed to be changed.And the second one indicates that the value of c shouldn't be changed.
Thus, in const char * argv[], argv is an array of const char* variables.This means the content that every element in argv points to is constant.Actually, each element points to a string, and argv is an array of strings storing "arguments" that CL passes to you.It's true that you can only read the arguments but modifying them.
Of course, compiler won't block you if const is missed here.If so, you can change the content of strings in your code and I guess nothing will happen, since these arguments are for you to read. :)
The C11 Standard declares that:
5.1.2.2.1 Program startup
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; 10), or in some other implementation-defined manner.
10) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char ** argv, and so on.
We will ignore this part: or in some other implementation-defined manner. since I'm interested only in definitions equivalent to the two above examples.
Would this be a valid definition for main since char* a[4] and char** are equivalent:
int main(int argc, char* argv[4]){/*...*/}
How about a VLA array, we are assuming printf will return a positive int value:
int main(int argc, char* argv[printf("Hello there!")]){/*...*/}
Yes, this is all covered by the "or equivalent". The footnote about renaming parameters or using typedefed types are just examples.
My favorite variant is
int main(int argc, char* argv[argc+1]){/*...*/}
because it has the most information about the semantic of all main functions.
int main(int argc, char* argv[4]){/*...*/}
is a valid signature of main. Compiler will ignore 4 in char argv[4] and it is equivalent to char argv[] = char **argv. Same goes with second signature.
I am just trying to write something like that:
u64 get_env(char *argv[]);
char* g_argv[];
static char * Sample ()
{
return (char*)get_env(g_argv);
}
int main(int argc, char *argv[])
{
g_argv = argv;
Sample();
}
Getting error: 'g_argv' has an incomplete type
warning: array 'g_argv' assumed to have one element [enabled by default]
I've tried many different ways. How to write it right?
The compiler sees you declaring g_argv as an array of char pointers, but you don't specify how many.
int main(int argc, char *argv[])
Despite what it looks like, argv is not an array; arrays aren't first class objects in C and cannot be passed to functions, only their addresses can. So because argv is a parameter, it's actually a pointer to a pointer. For this reason I think it's better to tell the truth and use
int main(int argc, char** argv)
which is exactly equivalent to the above. This confusion in the language has led you to
char* g_argv[];
You're saying this is an array of pointers, without saying how big the array is, but that's not what you want; you want a pointer to the first of several pointers:
char** g_argv;
That fixes the problem you asked about, but I wonder about this declaration:
u64 get_env(char *argv[]);
Why declare it as returning u64 when the name and usage clearly indicate that it returns a char*? Actually, you should not be declaring it here at all ... it should be declared in a header file that specifies the API that includes get_env. Hopefully that header file declares it as returning a char*, and then you can remove the cast from
return (char*)get_env(g_argv);
My c skills are very rusty, so I apologize if this is a dumb question, but I could not even think were to look for the answer to this simple question.
This code compiles without any warnings:
#include <ruby.h>
int run_script( int argc, char *argv[] ) {
ruby_sysinit(&argc, &argv);
}
But when I compile this code, I get the following warning:
#include <ruby.h>
int run_script( char * parameters ) {
int argc=0;
char *argv[1];
ruby_sysinit(&argc, &argv);
}
run_script_3.c: In function 'run_script':
run_script_3.c:7: warning: passing argument 2 of 'ruby_sysinit' from incompatible pointer type
it seems like i am passing the same pointer type in both cases.
The problem is that an array in formal parameter declaration is equivalent to pointer. Declaration of
int run_script( int argc, char *argv[] ) { ... }
is equivalent to
int run_script( int argc, char **argv) { ... }
because you can not send an array as parameter. You can send only a pointer and even if you put an array as actual parameter it is always converted to a pointer. Then if you put &argv you are getting address of this parameter, so it is an address in system stack where argv's value is stored.
On the other hand array in code is still an array, which is different type. In your case &argv is of type char *** inside the first version of run_script while it is of type char *(*)[1] in the second version. It looks like the same type, but it is not. In run time, there is even bigger difference, because your two invocations are sending two completely different values to ruby_sysinit.
Your second example:
int run_script( char * parameters ) {
int argc=0;
char *argv[1];
ruby_sysinit(&argc, &argv);
}
will probably cause segfault because opearator & applied on an array gives the pointer to the first element of the array. So the call ruby_sysinit(&argc, &argv); is sending the same values as ruby_sysinit(&argc, argv);, i.e. a value which points to char*, not to pointer to char* as expected by ruby_sysinit.
The signature of ruby_sysinit is as follows (correct me if I picked the wrong ruby version, I don't have the header file on my system):
void ruby_sysinit(int *argc, char ***argv);
This means that the following compiles:
extern void ruby_sysinit(int *argc, char ***argv);
int run_script(char * params) {
int argc = 0;
char **argv;
ruby_sysinit(&argc, &argv);
}
Now, when you declare char *argv[1], you tell the compiler that this is an array with one element. This is not the same as char **argv.
EDIT: you might find this question on SO and this article (as linked in the other question) useful.