C get the main arguments from the function. Main function arguments. Using Command Line Arguments


Sometimes when starting a program it is useful to pass some information to it. Typically this information is passed to main() via command line arguments. Command line argument is information that is entered on the operating system command line following the program name. For example, to start compiling a program, you need to type something like the following on the command line after the prompt:

Cc program_name

program_name is a command line argument; it specifies the name of the program you are about to compile.

To accept command line arguments, two special built-in arguments are used: argc and argv. The argc parameter contains the number of arguments on the command line and is an integer, and it is always at least 1, because the first argument is the name of the program. And the argv parameter is a pointer to an array of pointers to strings. In this array, each element points to a command line argument. All command line arguments are strings, so the conversion of any numbers into the desired binary format must be provided in the program when it is developed.

Here is a simple example of using a command line argument. The word Hello and your name are displayed on the screen, which must be specified as a command line argument.

#include #include int main(int argc, char *argv) ( if(argc!=2) ( printf("You forgot to enter your name.\n"); exit(1); ) printf("Hello %s", argv); return 0; )

If you called this program name (name) and your name is Tom, then to run the program you should enter name Tom into the command line. As a result of executing the program, the message Hello, Tom will appear on the screen.

In many environments, all command line arguments must be separated by a space or tab. Commas, semicolons, and similar characters are not considered delimiters. For example,

Run Spot, run

consists of three character strings, while

Eric, Rick, Fred

represents a single character string - commas, as a rule, are not considered delimiters.

If a string contains spaces, you can enclose the string in double quotes in some environments to prevent it from producing multiple arguments. As a result, the entire string will be considered one argument. To learn more about how your operating system sets command line parameters, review your operating system's documentation.

It is very important to declare argv correctly. Here's how it's done most often:

Char *argv;

Empty square brackets indicate that the array has an indefinite length. Individual arguments can now be accessed by indexing the argv array. For example, argv points to the first character string, which is always the program name; argv points to the first argument and so on.

Another small example of using command line arguments is the following program, countdown. This program counts backwards, starting from some value (specified on the command line), and beeps when it reaches 0. Note that the first argument, containing the starting value, is converted to an integer value using the standard atoi function (). If the second command line argument (and if we consider the program name as an argument, then the third) is the line “display” (display), then the result of the count (in reverse order) will be displayed on the screen.

/* Program for counting in reverse order. */ #include #include #include #include int main(int argc, char *argv) ( int disp, count; if(argc<2) { printf("В командной строке необходимо ввести число, с которого\n"); printf("начинается отсчет. Попробуйте снова.\n"); exit(1); } if(argc==3 && !strcmp(argv, "display")) disp = 1; else disp = 0; for(count=atoi(argv); count; --count) if(disp) printf("%d\n", count); putchar("\a"); /* здесь подается звуковой сигнал */ printf("Счет закончен"); return 0; }

Please note that if command line arguments are not specified, an error message will be displayed. Programs that take command line arguments often do the following: When the user runs these programs without entering the required information, they display instructions on how to correctly specify the arguments.

To access an individual character of one of the command line arguments, enter a second index into argv. For example, the following program prints, character by character, all the arguments with which it was called:

#include int main(int argc, char *argv) ( int t, i; for(t=0; t

Remember, the first index of argv provides access to the string, and the second index provides access to its individual characters.

Typically, argc and argv are used to give the program the initial commands that it will need when it starts. For example, command line arguments often specify information such as a file name, an option, or an alternative behavior. Using command line arguments gives your program a "professional look" and makes it easier to use in batch files.

The names argc and argv are traditional, but not required. You can call these two parameters in the main() function whatever you want. Additionally, some compilers may support additional arguments for main(), so be sure to check your compiler's documentation.

When a program does not require command line parameters, it is most common to explicitly declare the main() function as having no parameters. In this case, the keyword void is used in the parameter list of this function.

Tags: Command Line Options

Command Line Options

C is a compiled language. After assembly, the program is an executable file (we do not consider creating dynamic libraries, drivers, etc.). Our programs are very simple and do not contain Runtime libraries, so they can be transferred to a computer with the same operating system (and similar architecture) and run there.

The program can accept parameters during startup. They are arguments to the main function. The general view of the main function is as follows

Void main(int argc, char **argv) ( ... )

The first argument of argc is the number of parameters passed to the function. The second argument is an array of strings – the parameters themselves. Since the parameters of a function can be anything, they are passed as strings, and the program itself must parse them and convert them to the desired type.

The first argument (argv) is always the program name. In this case, the name is displayed depending on where the program was launched from.

#include #include void main(int argc, char **argv) ( printf("%s", argv); )

Now let's learn how to work a little with the command line. This will be needed in order to pass arguments to our program. The Win+R key combination brings up the Run window. Type cmd in it and you will open the command line. You can also find cmd.exe by searching in the Start menu. In Unix-like operating systems, you can call the terminal program.

We won't be learning too many commands. Only those that are needed for work.

The cd command, standard for all operating systems, navigates to the desired folder. There are two reserved names - . (dot) and.. (two dots). The dot is the name of the current folder.

Doesn't go anywhere

Accessing the parent folder

Go to parent folder

To go to the desired one, write the CD address. For example, you need to go to windows to the folder C:\Windows\System32

Cd C:\Windows\System32

In Linux, if you need to go to the /var/mysql folder

Cd /var/mysql

If the path contains spaces, it is written in double quotes

Cd "D:\Docuents and Settings\Prolog"

The terminal has the following useful features: if you press the up arrow, the previous executed command will appear. If you press tab, the terminal will try to complete the line to a command known to it, or complete the path, going through all the folders and files in the current folder.
Type cd C:\
press tab and see what happens.

Another important command, dir on Windows and ls on Linux, displays the contents of the current folder (the folder you are currently in) to the console.

Your program has returned its full name. Go to the folder where your program is located and look at its contents


Now that we've navigated to our folder, we can run our program. To do this, type her name.


Note that the name has changed. Since the program is called from its own folder, the relative name is displayed. Now let's change the program and make it print all the arguments. which were given to her.

#include #include void main(int argc, char **argv) ( int i; for (i = 0; i< argc; i++) { printf("%s\n", argv[i]); } }

Assemble the project. Before assembling, make sure the program is closed. Now call the program, passing it different arguments. To do this, write the name of the program and the arguments separated by a space


Let's now write a program that takes two number arguments and prints their sum

#include #include #include void main(int argc, char **argv) ( int a, b; if (argc != 3) ( printf("Error: found %d arguments. Needs exactly 2", argc-1); exit(1); ) a = atoi(argv); b = atoi(argv); printf("%d", a + b); )

Let's collect and call


This is how most programs work. By clicking on a shortcut, you call the program to which it refers. Most programs also accept various arguments. For example, you can call the firefox browser from the command line and pass the arguments
firefox.exe "www.mozilla.org" "site" and it will immediately open the sites at the specified addresses in two tabs.

Many standard commands also have parameters. In Windows it is customary that they begin with a forward slash, in Unix with a minus or two minuses. For example

Displays only folders, but in the linux terminal

Ls -l lists all files and folders with attributes

To view additional Windows commands, type help at the command line or see the manual (it's easy to find on the Internet). For Linux there are many more commands and their options, and some of them are independent programming languages, so it’s worth learning at least the minimum set and their options.

Borland C++ supports three arguments to main(). The first two are the traditional argc and argv. These are the only arguments to main() defined by the ANSI C standard. They allow command line arguments to be passed to the program. Command line arguments are the information that follows the program name on the operating system command line. For example, when a program is compiled using the Borland line compiler, it is typically typed bcc program_name

Where program_name is a program that needs to be compiled. The program name is passed to the compiler as an argument.

The argc parameter contains the number of command line arguments and is an integer. It is always equal to at least 1, since the program name qualifies as the first argument. The argv parameter is a pointer to an array of character pointers. Each element of this array points to a command line argument. All command line arguments are strings. All numbers are converted by the program into internal format. The following program prints "Hello" followed by the username when typed directly after the program name:

#include

{
if(argc!=2)
{
printf("You forgot to type your name\n");
return 1;
}
printf("Hello %s", argv);
return 0;
}

If you call this program name, and the user name is Sergey, then to start the program you should type:
name Sergey.
As a result of the program the following will appear:
"Hello Sergey."

Command line arguments must be separated by spaces or tabs. Commas, semicolons, and similar characters are not considered delimiters. For example:

Consists of three lines, while

Herb,Rick,Fred

This is one line - commas are not delimiters.

If you need to pass a string containing spaces or tabs as a single argument, you must enclose it in double quotes. For example, this is one argument:

"this is a test"

It is important to declare argv correctly. The most typical method is:

Empty parentheses indicate that the array does not have a fixed length. You can access individual elements using argv indexing. For example, argv points to the first line, which always contains the program name. argv points to the next line and so on.

Below is a small example of using command line arguments. It counts down from the value specified on the command line and emits a signal when it reaches zero. Note that the first argument contains a number converted to an integer using the standard atoi() function. If the string "display" is present as the second argument, then the counter itself will be displayed on the screen.

/* counting program */

#include
#include
#include
int main(int argc, char *argv)
{
int disp, count;
if(argc<2)
{
printf("You must enter the length of the count\n");
printf("on the command line. Try again.\n");
return 1;
}
if (argc==3 && !strcmp(argv,"display")) disp = 1;
else disp = 0;
for(count=atoi(argv); count; -count)
if (disp) printf("%d ", count);
printf("%c", "\a"); /* on most computers this is a call */
return 0;
}

Please note that if no arguments are specified, an error message appears. This is most typical for programs that use command line arguments to issue instructions if an attempt was made to run the program without the correct information.

To access individual command line characters, add a second index to argv. For example, the following program prints out all the arguments it was called with, one character at a time:

#include
int main(int argc, char *argv)
{
int t, i;
for(t=0; t {
i = 0;
while(argv[t][i])
{
printf("%c", argv[t][i]);
}
printf(" ");
}
return 0;
}

We must remember that the first index is for accessing a string, and the second is for accessing a character in a string.

Typically argc and argv are used to obtain source commands. It is theoretically possible to have up to 32767 arguments, but most operating systems don't even allow you to get close to that. Typically these arguments are used to specify a file name or options. Using command line arguments gives the program a professional look and allows the program to be used in batch files.

If you include the WILDARGS.OBJ file supplied with Borland C++, you can use templates in *.EXE type arguments. (Borland C++ automatically handles wildcards and increments argc accordingly.) For example, if you connect WILDARGS.OBJ to the following program, it will tell you how many files match the filename specified on the command line:

/* Link this program with WILDARGS.OBJ */

#include
int main(int argc, char *argv)
{
register int i;
printf("%d files match specified name\n", argc-1);
printf("They are: ");
for(i=1; i printf("%s ", argv[i]);
return 0;
}

If we call this program WA, then run it as follows, we will get the number of files with the EXE extension and a list of the names of these files:

In addition to argc and argv, Borland C++ also provides a third command line argument -env. The env parameter allows a program to access information about the operating system environment. The env parameter must follow argc and argv and is declared as follows:

As you can see, env is declared in the same way as argv. Just like argv, it is a pointer to an array of strings. Each line is an environment string defined by the operating system. The env parameter has no equivalent argc parameter that tells how many environment rows there are. Instead, the last line of the environment is null. The following program prints all the environment strings currently defined in the operating system:

/* this program displays all the environment lines */

#include
int main(int argc, char *argv, char *env)
{
int t;
for(t=0; env[t]/ t++)
printf("%s\n", env[t]);
return 0;
}

Please note that although argc and argv are not used by the program, they must be present in the parameter list. C doesn't know the parameter names. Instead, their use is determined by the order in which the parameters are declared. In fact, you can call the parameter whatever you like. Since argc, argv, and env are traditional names, it is best to continue to use them so that anyone reading the program can instantly understand that these are arguments to the main() function.

A typical task for programs is to look up a value defined in an environment string. For example, the contents of the PATH line allow programs to use search paths. The following program demonstrates how to find strings that declare standard search paths. It uses the standard library function strstr(), which has the following prototype:

Char *strstr(const char *str1, const char *str2);

The strstr() function searches for the string pointed to by str1 in the string pointed to by str2. If such a string is found, a pointer to the first position is returned. If no matches are found, the function returns NULL.

/* the program searches among the environment strings for a line containing PATH */

#include
#include
int main (int argc, char *argv, char *env)
{
int t;
for(t=0; env[t]; t++)
{
if(strstr(env[t], "PATH"))
printf("%s\n", env[t]);
}
return 0;
}

It happens that data is transferred to a program from the command line when it is called. Such data is called command line arguments. It looks like this, for example:

./a.out test.txt ls -lt /home/peter/

Here the programs a.out (from the current directory) and ls (from the same directory specified in the PATH environment variable) are called. The first program from the command line receives one word - test.txt, the second - two: -lt and /home/peter/.

If the program is written in C, then when it is launched, control is immediately transferred to the main() function, therefore, it is the function that receives the command line arguments that are assigned to its parameter variables.

Previously, we defined the main() function as if it takes no parameters and returns nothing. In fact, in the C language, any function by default (if nothing else is defined) returns an integer. You can be sure of this. If you write the code this way:

main() ( printf ("Hi \n") ; return 0 ; )

Then no warning or error will occur during compilation. The same thing happens if you write int main() . This proves that the function by default returns an integer and not nothing (void). Although what a function returns can always be “overridden”, for example, voidmain() or float main() .

When calling a program from the command line, the following pair of data is always passed into it:

  1. integer, indicating the number of words (elements separated by spaces) on the command line when called,
  2. pointer to an array of strings, where each line is a separate word from the command line.

Keep in mind that the program name itself also counts. For example, if the call looks like this:

./a.out 12 theme 2

Then the first argument of the program has the value 4, and the array of strings is defined as ("./a.out", "12", "theme", "2").

Note the terminology, there are only two program arguments (a number and an array), but as many command line arguments as you like. Command line arguments are "converted" into program arguments (into main() function arguments).
This data (number and pointer) is passed to the program even when it is simply called by name without passing anything to it: ./a.out. In this case, the first argument has the value 1, and the second points to an array consisting of just one line ("./a.out").

Just because data is passed into the program does not mean that the main() function must accept it. If the main() function is defined without parameters, then it is not possible to access the command line arguments. Although nothing prevents you from transmitting them. There will be no error.

To access the data passed to the program, it must be assigned to variables. Since the arguments are immediately passed to main() , its header should look like this:
main (int n, char *arr)

The first variable (n) contains the number of words, and the second variable contains a pointer to an array of strings. Often the second parameter is written as **arr . However, it's the same thing. Recall that the array of strings itself contains pointers to strings as its elements. And we pass a pointer to the first element of the array to the function. It turns out that we are passing a pointer to a pointer, i.e. **arr.

Exercise
Write a program like this:

#include int main(int argc, char ** argv) ( int i; printf ("%d \n", argc) ; for (i= 0 ; i< argc; i++ ) puts (argv[ i] ) ; }

It displays the number of words on the command line when it is called, and each word on a new line. Call it without command line arguments and with arguments.

In the program we used the parameter variables argc and argv. It is customary to use these names, but in fact they can be anything. It's better to stick to this standard so that your programs are more understandable not only to you, but also to other programmers.

The practical significance of transferring data to the program

If you have any experience with the GNU/Linux command line, you know that most commands have switches and arguments. For example, when viewing the contents of directories, copying, moving, the file system objects on which the command is executed are specified as arguments. The features of its implementation are determined using keys. For example, in a team

Cp -r ../les_1 ../les_101

cp is the command name, -r is the switch, and ../les_1 and ../les_101 are the command arguments.

In general, most often, file addresses and “modifiers” (these are keys) of the program execution process are transferred to programs when they are launched.

Let's write a program that opens files specified by the user on the command line for writing or adding and writes (adds) there the same information that the user enters from the keyboard during program execution:

#include #include main (int argc, char ** argv) ( int i, ch; FILE * f[ 5 ] ; if (argc< 3 || argc >7) (puts ( "Invalid number of parameters") ; return 1 ; ) if (strcmp (argv[ 1 ] , "-w" ) != 0 && strcmp (argv[ 1 ] , "-a" ) != 0 ) ( puts ( "The first parameter can be either -w or -a") ; return 2 ; ) for (i= 0 ; i< argc- 2 ; i++ ) { f[ i] = fopen (argv[ i+ 2 ] , argv[ 1 ] + 1 ) ; if (f[ i] == NULL) { printf ("The file %s cannot be opened\n ", argv[ i+ 2 ] ) ; return 3 ; ) ) while ((ch = getchar () ) != EOF) for (i= 0 ; i< argc- 2 ; i++ ) putc (ch, f[ i] ) ; for (i= 0 ; i < argc- 2 ; i++ ) fclose (f[ i] ) ; return 0 ; }

Explanations for the code:

  1. An array of five file pointers is created. Therefore, you can open no more than five files at the same time. The file pointer of the first file will be stored in array element f, the second - in f, etc.
  2. The number of command line arguments is checked. There should be at least three of them, because... the first is the program name, the second is the file opening mode, the third is the first or only file to be written to. Since the program allows you to open only five files, the total number of command line arguments cannot be more than seven. Therefore, if the number of arguments is less than 3 or more than 7, then the program ends, because The return statement causes the function to exit, even if there is more code after it. A value returned from a function that is not equal to 0 can be interpreted by the parent process as a message that the program terminated with an error.
  3. Checks the validity of the second command line argument. If it is neither "-w" nor "-a", then the conditional expression in the second if returns 1 (true). The strcmp() function allows you to compare strings and returns 0 if they are equal.
  4. The for loop opens files at the specified addresses, which begin with the third element of the argv array. This is why 2 is added to i to get the elements of the argv array, starting from the third. The argc-2 expression indicates the number of filenames passed; because argc stores the total number of command line arguments, the first two of which are not file names.
  5. The expression argv+1 allows you to “cut” the substring “w” (or “a”) from the string “-w” (or “-a”), because argv is essentially a pointer to the first element of the string. By adding one to the pointer, we move it to the next element of the array.
  6. If the file cannot be opened, the fopen() function returns NULL. In this case, the program ends.
  7. Every character entered by the user on the keyboard is written to all open files.
  8. At the end the files are closed.

One day I became interested in the contents of the stack of the main function of a process in Linux. I did some research and now I present to you the result.

Options for describing the main function:
1. int main()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv)
5. int main(int argc, char **argv, char **env, char **apple)

Argc - number of parameters
argv - null-terminal array of pointers to command line parameter strings
env is a null-terminal array of pointers to strings of environment variables. Each line in the format NAME=VALUE
auxv - array of auxiliary values ​​(only available for PowerPC)
apple - path to the executable file (on MacOS and Darwin)
An auxiliary vector is an array with various additional information, such as the effective user identifier, setuid bit attribute, memory page size, etc.

The size of the stack segment can be found in the maps file:
cat /proc/10918/maps

7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0

Before the loader transfers control to main, it initializes the contents of the arrays of command line parameters, environment variables, and auxiliary vector.
After initialization, the top of the stack looks something like this for the 64-bit version.
Senior address on top.

1. 0x7ffffffff000 The top point of the stack segment. The call causes a segfault
0x7ffffffff0f8 NULL void* 8 0x00"
2. filename char 1+ "/tmp/a.out"
char 1 0x00
...
env char 1 0x00
...
char 1 0x00
3. 0x7fffffffe5e0 env char 1 ..
char 1 0x00
...
argv char 1 0x00
...
char 1 0x00
4. 0x7fffffffe5be argv char 1+ "/tmp/a.out"
5. Array of random length
6. data for auxv void* 48"
AT_NULL Elf64_auxv_t 16 {0,0}
...
auxv Elf64_auxv_t 16
7. auxv Elf64_auxv_t 16 Ex.: (0x0e,0x3e8)
NULL void* 8 0x00
...
env char* 8
8. 0x7fffffffe308 env char* 8 0x7fffffffe5e0
NULL void* 8 0x00
...
argv char* 8
9. 0x7fffffffe2f8 argv char* 8 0x7fffffffe5be
10. 0x7fffffffe2f0 argc long int 8" number of arguments + 1
11. Local variables and arguments of functions called before main
12. Local variables main
13. 0x7fffffffe1fc argc int 4 number of arguments + 1
0x7fffffffe1f0 argv char** 8 0x7fffffffe2f8
0x7fffffffe1e8 env char** 8 0x7fffffffe308
14. Local Function Variables

" - I didn’t find descriptions of the fields in the documents, but they are clearly visible in the dump.

I haven’t checked for 32 bits, but most likely it’s enough to just divide the sizes by two.

1. Accessing addresses above the top point causes a Segfault.
2. A string containing the path to the executable file.
3. Array of strings with environment variables
4. Array of strings with command line parameters
5. Array of random length. Its selection can be disabled with the commands
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. Data for the auxiliary vector (for example, the string “x86_64”)
7. Auxiliary vector. More details below.
8. Null-terminal array of pointers to strings of environment variables
9. Null-terminal array of pointers to command line parameter strings
10. A machine word containing the number of command line parameters (one of the arguments of the “major” functions, see paragraph 11)
11. Local variables and arguments of functions called before main(_start,__libc_start_main..)
12. Variables declared in main
13.Arguments of the main function
14. Variables and arguments of local functions.

Auxiliary vector
For i386 and x86_64, it is not possible to obtain the address of the first element of the auxiliary vector, but the contents of this vector can be obtained in other ways. One of them is to access the memory area immediately behind the array of pointers to strings of environment variables.
It should look something like this:
#include #include int main(int argc, char** argv, char** env)( Elf64_auxv_t *auxv; //x86_64 // Elf32_auxv_t *auxv; //i386 while(*env++ != NULL); //looking for the beginning of the auxiliary vector for ( auxv = (Elf64_auxv_t *)env; auxv->a_type != AT_NULL; auxv++)( printf("addr: %p type: %lx is: 0x%lx\n", auxv, auxv->a_type, auxv->a_un .a_val); ) printf("\n (void*)(*argv) - (void*)auxv= %p - %p = %ld\n (void*)(argv)-(void*)(&auxv) =%p-%p = %ld\n ", (void*)(*argv), (void*)auxv, (void*)(*argv) - (void*)auxv, (void*)(argv) , (void*)(&auxv), (void*)(argv) - (void*)(&auxv)); printf("\n argc copy: %d\n",*((int *)(argv - 1 ))); return 0; )
The Elf(32,64)_auxv_t structures are described in /usr/include/elf.h. Functions for filling structures in linux-kernel/fs/binfmt_elf.c

Second way to get the contents of a vector:
hexdump /proc/self/auxv

The most readable representation is obtained by setting the LD_SHOW_AUXV environment variable.

LD_SHOW_AUXV=1 ls
AT_HWCAP: bfebfbff //processor capabilities
AT_PAGESZ: 4096 //memory page size
AT_CLKTCK: 100 //update frequency times()
AT_PHDR: 0x400040 //header information
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 //interpreter address, that is, ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //program entry point
AT_UID: 1000 //user and group identifiers
AT_EUID: 1000 //nominal and effective
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //whether the setuid flag is raised
AT_RANDOM: 0x7fff30bdc809 //address of 16 random bytes,
generated at startup
AT_SYSINFO_EHDR: 0x7fff30bff000 //pointer to the page used for
//system calls
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
On the left is the name of the variable, on the right is the value. All possible variable names and their descriptions can be found in the elf.h file. (constants with AT_ prefix)

Return from main()
After the process context is initialized, control is transferred not to main(), but to the _start() function.
main() is already called from __libc_start_main. This last function has an interesting feature - it is passed a pointer to a function that should be executed after main(). And this pointer is passed naturally through the stack.
In general, the arguments to __libc_start_main look like this, according to the file glibc-2.11/sysdeps/ia64/elf/start.S
/*
* Arguments for __libc_start_main:
* out0: main
* out1: argc
* out2: argv
* out3:init
* out4: fini //function called after main
* out5: rtld_fini
* out6: stack_end
*/
Those. to get the address of the fini pointer, you need to shift two machine words from the last local variable main.
Here's what happened (workability depends on the compiler version):
#include void **ret; void *leave; void foo())( void (*boo)(void); //function pointer printf("Stack rewrite!\n"); boo = (void (*)(void))leave; boo(); // fini () ) int main(int argc, char *argv, char *envp) ( unsigned long int mark = 0xbfbfbfbfbfbfbfbf; //mark from which we will work ret = (void**)(&mark+2); // extract the address , a function called after completion (fini) leave = *ret; // remember *ret = (void*)foo; // grind return 0; // call the function foo() )

I hope it was interesting.
Good luck.

Thanks to user Xeor for the useful tip.

Continuing the topic:
Routers

Most email clients, including Gmail, Mail.ru, Microsoft Outlook, Mozilla Thunderbird, allow you to put multiple recipients in the Cc (in English...