Where Are C/C++ Main Function's Parameters

Where are C/C++ main function's parameters?

It's actually a combination of compiler dependence and operating system dependence. main() is a function just like any other C function, so the location of the two parameters argc and argv will follow standard for the compiler on the platform. e.g. for most C compilers targeting x86 they will be on the stack just above the return address and the saved base pointer (the stack grows downwards, remember). On x86_64 parameters are passed in registers, so argc will be in %edi and argv will be in %rsi. Code in the main function generated by the compiler then copies them to the stack, and that is where later references point. This is so the registers can be used for function calls from main.

The block of char*s that argv points to and the actual sequences of characters could be anywhere. They will start in some operating system defined location and may be copied by the pre-amble code that the linker generates to the stack or somewhere else. You'll have to look at the code for exec() and the assembler pre-amble generated by the linker to find out.

The parameters of the Main function in C++

Let's see what is happening in your example on case by case basis:

Case 1

Here we consider the statement:

char* p = "Hello";

On the right hand side of the above statement, we've the string literal "Hello" which is of type const char[6]. There are two ways to understand why the above statement didn't work.

  1. In some contexts, const char[6] decays to a const char* due to type decay. This basically means that on the right hand side we will have a const char* while on the left hand side we have a char*. Note also that this means that on the right hand side we've a low-level const but on the left hand side we don't have any low-level const. So, the given statement won't work. For the statement to work we've to make sure that the left hand side should've either same or greater low-level const qualifier than the right hand side.

A few example would illustrate the point:

int arr1[] = {1,2,3};
int* ptr1 = arr1; //this works because arr1 decays to int* and both sides have no low level const

const int arr2[] = {1,2,3};
int* ptr2 = arr2; //won't work, right hand side will have a low level const(as arr2 decays to const char*) while the left hand side will not have a low level const

const int* ptr3 = arr2; //this works, both side will have a low level const

  1. The second way(which is basically equivalent to the 1st) to understand this is that since "Hello" is of type const char[6], so if we are allowed to write char* p = "Hello"; then that would mean that we're allowed to change the elements of the array. But note that the type const char[6] means that the char elements inside the array are immutable(or non-changable). Thus, allowing char* p = "Hello"; would allow changing const marked data, which should not happen(since the data was not supposed to change as it was marked const). So to prevent this from happening we have to use const char* p = "Hello"; so that the pointer p is not allowed to change the const marked data.


Case 2

Here we consider the declaration:

int main (int argc, char *argv[])

In the above declaration, the type of the second parameter named argv is actually a char**. That is, argv is a pointer to a pointer to a char. This is because a char* [] decays to a char** due to type decay. For example, the below given declarations are equivalent:

int main (int argc, char *argv[]); //first declaration
int main (int argc, char **argv); //RE-DECLARATION. Equivalent to the above declaration

In other words, argv is a pointer that points to the first element of an array with elements of type char*. Moreover, each elements argv[i] of the array(with elements of type char*) itself point to a character which is the start of a null terminated character string. That is, each element argv[i] points to the first element of an array with elements of type char(and not const char). Thus, there is no need for const char*. A diagram is given for illustration purposes:

argc and argv

Why can C main function be coded with or without parameters?

Making it work has to do with the binary format of the executable and the OS's loader. The linker doesn't care (well it cares a little: it needs to mark the entry point) and the only caller routine is the loader.

The loader for any system must know how to bring supported binary format into memory and branch into the entry point. This varies slightly by system and binary format.


If you have a question about a particular OS/binary format, you may want to clarify.

what is the purpose of arguments in main method in C language

The signature of main is:

int main(int argc, char **argv);

Where argc is the number of command line arguments passed in, which includes the actual name of the program, as invoked by the user.

argv contains the actual arguments, starting with index 1, since index 0 is the program name.

So, if you run your program like this:

./program hello world

Then:

argc would be 3.

argv[0] would be ./program.

argv[1] would be hello.

argv[2] would be world.

I hope this is clear enough for you.

If you want to understand it more clearly, go to these: Link, Link

Function arguments alignment in C

&cnt and &adr are addresses of parameters. Parameters are variables local to the function that are initialized to the argument values passed by the caller. The compiler is not required to use the same space for parameters that is used to pass the arguments.

When an argument is passed on the stack, a compiler might or might not reuse its stack space for the parameter. When an argument is passed in a processor register and an address is needed for it, as because a program takes the address and prints it, then the compiler has to reserve space for the parameter on the stack, copy the value from the register to the stack space (as with a store instruction), and use the address of the stack space.

When the compiler is laying out stack space for this, it does not need to care that cnt and adr are consecutive parameters. It can organize data about all the stack space it needs—for parameters, for local variables, for the return address, for its own purposes, whatever—and then just assign stack space for those things in any order. So you should not expect there to be any close relationship between the addresses of cnt and adr.

(For functions with variable arguments, the compiler needs someway to implement the variable argument list features. This usually involves having the variable arguments consecutive in memory after the last fixed argument, which would be adr in the example. This does not impose any relationship between cnt and adr.)

How do you pass a function as a parameter in C?

Declaration

A prototype for a function which takes a function parameter looks like the following:

void func ( void (*f)(int) );

This states that the parameter f will be a pointer to a function which has a void return type and which takes a single int parameter. The following function (print) is an example of a function which could be passed to func as a parameter because it is the proper type:

void print ( int x ) {
printf("%d\n", x);
}

Function Call

When calling a function with a function parameter, the value passed must be a pointer to a function. Use the function's name (without parentheses) for this:

func(print);

would call func, passing the print function to it.

Function Body

As with any parameter, func can now use the parameter's name in the function body to access the value of the parameter. Let's say that func will apply the function it is passed to the numbers 0-4. Consider, first, what the loop would look like to call print directly:

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}

Since func's parameter declaration says that f is the name for a pointer to the desired function, we recall first that if f is a pointer then *f is the thing that f points to (i.e. the function print in this case). As a result, just replace every occurrence of print in the loop above with *f:

void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}

Source

How to use command line argument in function calls and parameters?

You have an array of strings in argv that looks like this:

{ "./cnp", "cut", "13", "5", "copy", "33", "7", "paste", "1", "input-b.txt", "output.txt" }

On the assumption that the last two arguments are always the input and output files, I would loop through the arguments from 1 to arc - 3 to process the commands e.g. the below sketch is not a complete solution but should give you some ideas.

if (argc < 3) 
{
// Handle the fact that there were not enough arguments.
}
else
{
int commandArgs = argc - 2;
for (int i = 1 ; i < commandArgs ; ++i) // Start at 1 to omit program name
{
if (strcmp(argv[i], "cut") == 0)
{
if (commandArgs - i < 2)
{
// Handle not enough args to cut
}
else
{
// You have a cut command, call cut or save it to call cut later
i += 2; // Skip the two parameters
}
}
else if (strcmp(argv[i], "copy") == 0)
{
// similar pattern to above
}
else if (strcmp(argv[i], "paste") == 0)
{
// similar pattern to above
}
else
{
// Handle invalid command error
}
}
}

Main function with three arguments

The third argument to main is normally called envp.

int main(int argc, char **argv, char **envp) {

Many compilers provide a third argument to main, but it is not specified in the C standard, so using it is undefined behaviour. If you try to port the code to a platform that doesn't provide a third parameter the program will most likely fail.

Is char *envp[] as a third argument to main() portable



Related Topics



Leave a reply



Submit