If I have, suppose, initialized a global variable F, and print its value in main function, 0 will be printed (as it should be).
But when i pass the argument int F in the main function while declaring the global variable F in exact same way as before, printing the value of F using gcc prints 1.
Can anyone explain why is that?
This is my code below.
#include<stdio.h>
int F;
int main(int F){
printf("F is %d\n", F);
return 0;
}
When your main function contains an argument with the same name as a global variable then the stub is refered to the local variable .. not the global variable
#include <stdio.h>
static int F;
int main(){
printf("F is %d", F);
return 0;
}
But when i pass the argument int F in the main function ? that F is nothing but argument count i.e argc.
In particular case you mentioned global F and F you declared in main() argument are different.
int main(int F){ printf("F is %d\n", F); return 0; }
Here printf() prints 1 because when you run your executable like ./a.out no of command line input is 1, it's similar to argc.
Your compiler could have warn you about argument provided to main(), compile with -Wall flag and read the warning. Also check the main() prototype. From the C standard
ISO/IEC 9899:1999
§5.1.2.2.1 Program startup
¶1 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 intand 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;9) or in some other implementation-defined manner.
In your posted code, main has an argument named F. Inside main, any references to F refer that variable, not the global one.
You make life unnecessarily harder by using improper names of variables. Most of the time, the arguments to main are named argc and argv -- argument count and argument values.
int main(int argc, char** argv) { ... }
It's good to use variable names that have meaning. Using int F; as a global variable is not meaningful either. Name it such that it is meaningful. Then, you will run into problems like you did a lot less.
You should make main() conform to the requirements of the standard, and you should print the global F as well as the argument F:
#include <stdio.h>
int F;
int main(int F, char **G)
{
printf("F is %d\n", F);
{
extern int F;
printf("%s: F is %d\n", G[0], F);
}
return 0;
}
When compiled (from source file quirky43.c to program quirky43), and run, I get:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror quirky43.c -o quirky43
$ ./quirky43
F is 1
quirky43: F is 0
$ ./quirky43 this is why you get command line arguments
F is 9
quirky43: F is 0
$
The first printf() is printing the first argument to main() (conventionally called argc, but there's nothing wrong with calling it F except that it is unexpected). The second one prints the global variable F (and also the program name, conventionally argv[0] but again there's nothing wrong with using G except that it is unexpected). The extern int F; inside a set of braces means that F in that statement block refers to a variable F defined outside the enclosing scope, which means the file scope variable F — which, it may be noted, is correctly initialized to 0. The 1 comes because you invoked the program without arguments, and the argument count includes the program name. It's also why the value printed was 9 when 8 arguments were added to the command line.
Note that another good compilation option to use is -Wshadow:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wshadow quirky43.c -o quirky43
quirky43.c: In function ‘main’:
quirky43.c:6:14: error: declaration of ‘F’ shadows a global declaration [-Werror=shadow]
int main(int F, char **G)
~~~~^
quirky43.c:4:5: note: shadowed declaration is here
int F;
^
cc1: all warnings being treated as errors
$
(Compilation with GCC 8.1.0 on a Mac running macOS High Sierra 10.13.5.)
Related
I have read about the evil of returning addresses of stack-based variables, but I am confused with the following case. In the function f I am returning the pointer p which holds the address of i, both of which are local variables. I expected to get some undefined behavior when I call the f function, but the call in the main function returns correctly the value of the local i namely 14. Is this just an accident and itself an undefined behavior, or why am I able to return that address to the outside world of the function?
#include <stdio.h>
char *f()
{
char *p;
char i =14;
p=&i;
return p;
}
int main()
{
printf("%d", *f());
return 0;
}
It is still undefined behavior and it just happens to work here.
The value of i is still on the stack because nothing has overwritten it yet
If you were to run it on a different architecture, or with different compiler settings it might not work.
If you were to do something like this, It no longer returns the correct value.
#include <stdio.h>
char *f()
{
char *p;
char i =14;
p=&i;
return p;
}
void g()
{
int a = 1;
int b = 3;
printf("%d",a+b);
}
int main()
{
char* c = f();
g();
printf("%s", c);
return 0;
}
If undefined behavior was guaranteed to give you wrong results, C programming would be so much easier.
Instead, you get weird behavior like this, where enabling basic optimizations breaks your program (Debian gcc 10.2.0-16):
$ gcc foo.c -o foo && ./foo
14
$ gcc -O foo.c -o foo && ./foo
0
Now your program will probably crash in prod, and any attempt to step through it in a debugger in dev will not show the problem.
I have two C files:
main.c
#include <stdio.h>
int sum(int n);
double array[2] = { 0.001, 1.0001 };
int main()
{
int val = sum(2);
printf("%d\n", val);
return 0;
}
sum.c
extern int array[2];
int sum(int n)
{
int i, ret = 0;
for (i = 0; i < n; i++) {
ret += array[i];
}
return ret;
}
I compile and link the files and then run the executable, but I am getting some unexpected output:
306318409
Why is that happening?
C Standard section 6.2.7/2 says
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
So anything could have happened. That's what you get when you lie to the compiler.
This really helps to make out the difference between compiling and linking .
When these two files where compiled :
main.c
implicitly declares a sum() function with return type as int*.
Has an array variable of type double* in it's list of variables
sum.c :
externed variable array allowed by compiler to get a value at link time and added to it's list of symbols .
defines a function sum which now uses the variable array with type as int* whose information was maintained by the compiler independently for this program that was externed .
Now at link time :
sum() call in main.c gets resolved from sum.c
sum.c had maintained the type of array variable as int* , while the extern variable was resolved by the double* type ,which however does not change the behaviour of variable array decided in sum() definition at compile time .
An array of doubles is stored with each in 8 bytes , while the sum() function assumed it would be stored per 4 bytes . So array[0] read the first 4 bytes and array[1] read the next 4 bytes , while however the number 0.001 in main.c from it's array[0] was itself stored in 8 bytes , leading to this undefined behavior.
This question already has answers here:
What should main() return in C and C++?
(19 answers)
Closed 8 years ago.
I understand why C requires a main function to begin the execution of a program, but of the now three books I've read entirely or in portion, none has explained why programs begin by declaring main as int, or with an argument of void:
int main(void)
can someone tell me what the purpose of this is?
The return value of main() is used to indicate success or failure to its parent process. More generally, it can be used to communicate back specific statuses as well, though C doesn't define those.
If main() returns 0 or EXIT_SUCCESS, then the program was successful. EXIT_FAILURE or non-zero, then it failed.
The void in the parameter list simply says that it takes no arguments. This is because of a (mis)feature of C which allows you to declare a function without fully specifying the paramters it takes. A function declared int func(); can be called with any number of parameters, but int func(void); can only becalled with zero.
Example
on linux,
two trivial programs:
$ cat ret0.c
int main (void) { return 0; }
$ cat ret42.c
int main (void) { return 42; }
Then in `bash` we can look at
$ ./ret0 ; echo $?
0
$ ./ret42 ; echo $?
42
So it's possible to use that status when calling your program.
The int return is there to give an error indicator back to the OS. return 0 means no error, all other codes (typically return 1) indicates the program could not finish successfully. Other programs (e.g., shell scripts) can use this error code to determine if your program executed its task, or ran into a problem.
void just means no arguments. It's the same as
int main()
{
/* program */
}
but more explicit.
A program can take command line arguments, in which case main must be defined as
int main(int argc /* number of arguments */, char *argv[] /* arguments)
{
/* program
}
Any good book on C should explain this.
First off let us forget about main. In C(not C++) if you define a function with no parameters like this
int f(){ return 0;}
It is legal to call such a function with any number of arguments:
int a = f(); /* legal */
int a = f("help", 1, 2.0); /* legal */
If you want your function f to only work with exactly no arguments you can amend it like this:
int f(void){return 0;}
int a = f(); /* legal */
int a = f("help", 1, 2.0); /* not legal as it has too many parameters */
The same thing applies to main() and main(void) . In most cases in the reasonable world most people would never care however I have encountered legal code that calls main within the program.
So declaring main like:
int main() {
/* Do a bunch of stuff here */
}
Allows for code elsewhere in your program to do this:
main();
main(1,2,3,4);
By declaring main(void) you add a compiler check that prevents the latter example main(1,2,3,4) from compiling.
Like any other function in C, main is also a function. Thus it has a return type and can
accept arguments.
int main(void)
Here int is the return type of main. Many people still use 'void' because they do not
update themselves with the current language standards. haccks's answer mentions about
the latest standard specifying the signature of main function.
Its general and good practice to have int as main's return type as it tells the parent process of main about the termination (success / failure) of the program.
Like any other function main is also capable of accepting arguments, but with an exception, i.e. the arguments to main are given before the execution of program starts. These are called "command line arguments".
main can accept arguments in two ways :
1. int main(void)
or
int main()
2. int main(int argc, char *argv[])
or
int main(int argc, char **argv)
The first one says that main is not expecting any arguments where as the second declara-
-tion expects the user to provide command line arguments to main.
Note : main should take either 0 or 2 arguments. If you try to give any number of
arguments other than these then it gives the following warning when you compile your code
warning: ‘main’ takes only zero or two arguments [-Wmain]
Edit : The above warning is displayed if you are using gcc.
I just noticed that a function, which is passed as an argument in C, is no more available in the main function for direct calling. the compilation of the code below produces the error
"../main.c:22:8: error: called object ‘hello’ is not a function or function pointer"
Code:
#include<stdio.h>
void hello(void)
{
printf("hello there\n");
}
void main(hello)
{
int y = 100;
printf("%i",y);
if (y==100)
hello();
}
is it the case or I did something wrong?
EDIT: I changed the main call to - void main(void hello (void)) Now there is no error in compilation but still the call to hello function after IF statement doesn't execute printf statement.
EDIT NO 2 : After reading many answer, I learnt that we can pass a pointer to a function as an argument to another function. passing whole function as argument is meaningless. Actually, this whole confusion arose out of the following opengl C code, which apparently ran successful in Eclipse IDE:
#include <GL/glut.h>
#include<GL/gl.h>// Header File For The GLUT Library
void init(void)
{
glClearColor (0.0,0.0,0.4,0.0);
glShadeModel(GL_FLAT);
}
void reshape (int w, int h)
{
glViewport(0,0, (GLsizei) w, (GLsizei)h); // indicates the shape of the available screen area into which the scene is mapped
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10,10,-10,10,-10,10);
}
void display (void)
{
int i,j;
while(1){
for (i=-10; i <=10; i++){
glClearColor (0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f(i,2,5);
glVertex3f(6,-i,-5);
glVertex3f(1,9,-1);
glEnd();
glFlush();}
}
}
int main (int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(500,500);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop ();
return 0;
}
Here if you notice the call glutDisplayFunc(display) APPARENTLY passes the display function as an argument.How this is happening?
You've managed to blur things horribly.
void main(hello) declares main (incorrectly) as returning nothing and taking a single argument of type int (implicit int). You can't call an int; hence your local variable hides the external function of the same name. The C89 and pre-standard C allowed the 'implicit int' notation; it is officially not allowed in C99 or C11, though many compilers will continue to allow it unless you ask them for warnings.
You should declare main() as either:
int main(void)
int main(int argc, char **argv)
Windows does allow void main(), sadly. C++ does not.
If you use GCC, compile with options like -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration (preferably with -Werror). Not all versions of GCC support all those options; use those that your version does support.
Incidentally, by declaring hello as an argument to main(), you are hiding or shadowing the external definition of the hello() function. This is standard C behaviour; a name defined at local scope hides different objects with the same name defined at outer scope levels. You can use the -Wshadow option to GCC to spot when you run into this as a problem.
Post-Edit
As I already asked, why on earth do you think the startup environment is going to pass a pointer-to-function to your main()?
The function definition:
void main(void hello(void))
still does not match one of the acceptable patterns.
Further, the startup code won't pass a pointer to function to your main(); it will basically call your code as if you'd written int main(int argc, char **argv) (or possibly int main(int argc, char **argv, char **envp)). You are guaranteed not to get a pointer-to-function passed to your main().
So, whatever else happens, you will not be successful. Typically, the value of argc (and perhaps part of argv) will be treated as a pointer to function (even though it isn't). All hell will break loose.
Simply define:
int main(void)
and call hello() directly in the body of main(). That's about all that makes sense.
For the record, this is what GCC says about the code in the question (as amended):
$ gcc -O3 -g -I/Users/jleffler/inc -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -Wshadow -c hello.c
hello.c:3:6: error: no previous prototype for ‘hello’ [-Werror=missing-prototypes]
void hello(void)
^
hello.c:8:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(void hello (void))
^
hello.c:8:6: error: first argument of ‘main’ should be ‘int’ [-Werror=main]
hello.c:8:6: error: ‘main’ takes only zero or two arguments [-Werror=main]
hello.c: In function ‘main’:
hello.c:8:16: error: declaration of ‘hello’ shadows a global declaration [-Werror=shadow]
void main(void hello (void))
^
hello.c:3:6: error: shadowed declaration is here [-Werror=shadow]
void hello(void)
^
cc1: all warnings being treated as errors
$
Passing pointers to functions — the OpenGL code
You can pass a pointer-to-function as an argument to any function that expects such an argument. However, main() is one of the functions you can't tinker with (the functions in the Standard C library should be treated as 'cannot be changed' either; ditto the operating system interfaces for the platform(s) you use).
In your OpenGL example code, it is perfectly legitimate to pass a function pointer like display or reshape to the glutDisplayFunc() and glutReshapeFunc() functions because they are designed to accept pointers to functions. Had you written your initial offering as:
#include <stdio.h>
static void hello(void)
{
printf("hello there\n");
}
static void invoke(void (*function)(void))
{
printf("-->> %s:\n", __func__);
function(); // Or (*function)();
printf("<<-- %s\n", __func__);
}
int main(void)
{
int y = 100;
printf("%i\n", y);
if (y == 100)
invoke(hello);
return 0;
}
there would have been no outcry from anyone — compiler or human. This is clean (C99 or C11) code that helps in understanding pointers to functions. If you write void invoke(void function(void)) without the explicit pointer, the compiler automatically converts the type to 'pointer to function taking no arguments and returning no value — aka void (*function)(void). So, you can write that if you prefer, though I prefer the explicit pointer notation, not least because inside a function, or as a global variable, you must use the explicit pointer notation, so using that with function arguments is consistent. Inside a function, writing:
void function(void);
declares a function, not a pointer to function variable; that must be written:
void (*function)(void) = hello; // Note no parentheses on hello!
Similarly at with variables at file scope. So, using the void (*function)(void) notation in function argument lists (in prototypes and definitions) is consistent with the rest of the language and is therefore the better notation to use.
The parameter hello shadows the global hello, so all appearances of hello within main refer to the parameter, not the function. And since the parameter is of type int (because you didn't specify a type and int is the default) and ints aren't functions (or function pointers), that's a type error.
main(hello)
is wrong
use
main()
I have an array that I declared and initialized in main called Edges.
I have also declared some functions in main that access the array called Edges.
The code compiles and works.
Why does it work? I thought variables declared in main aren't global.
Edit: see Sourav's code.
Actually, if you declare a function inside a function, the inner function is just visible to the outer function and NOT in global scope. So, the variables declared by you and the inner function [to be appropriate, the code block] is having same scope. Hence, no issues accessing the variable.
Check this one
code
#include <stdio.h>
#include <stdlib.h>
int innerfunc();
int main()
{
int outer = 5;
int innerfunc()
{
printf("outer is %d\n", outer);
}
innerfunc();
return 0;
}
output
[sourav#infba01383 so_overflow]# ./a.out
outer is 5
[sourav#infba01383 so_overflow]#
You can't declare a function inside a function in C. This means that you can't declare function(s) inside main. Compile your code with -pedantic flag and you will see this warning for sure;
[Warning] ISO C forbids nested functions [-Wpedantic]
I compiled this code
#include <stdio.h>
void void print(int *);
int main()
{
int a[2] = {1,3};
void print(int *a)
{
printf("%d", *a);
}
print(a);
return 0;
}
and getting the warning
[Warning] ISO C forbids nested functions [-Wpedantic]
First of all, as most answers have mentioned, it is a gcc extension; not part of standard C.
Below answer is strictly confined to gcc.
gcc does treat them as any other function.
e.g. Check below code:
(I took liberty to extend your code as below:)
#include <stdio.h>
#include <stdlib.h>
typedef int operation(int num1, int num2); // for function pointer...
operation* getOperation(char oper)
{
int a=10;
int add(int x, int y){return x+y+a;}
int sub(int x, int y){return x-y+a;}
int nop(int x, int y){return a;}
if(oper=='+')return add;
if(oper=='-')return sub;
return nop;
}
int main()
{
operation *my_op;
my_op=getOperation('+');
printf("%d\n",my_op(5,3));
my_op=getOperation('-');
printf("%d\n",my_op(5,3));
return 0;
}
If you compile it with gcc -S & check the assembly code generated, it would show that
The functions - getOperation & main - are converted to assembly, without any name change. Thus these can be called from any function (in this or even from other file).
e.g.
.globl getOperation /*This line will be missing in case of static functions.*/
.type getOperation, #function
The functions - add, sub, nop - are converted to assembly with some unique random suffix.
e.g.
/*No .globl line is printed here.*/
.type add.2685, #function
Since the names are changed, you cannot call them from other functions. Only the 'parent function' (getOperation in this case) has the information of the function name. (Check for c variable scope for more details.)
However, you can use them in other functions, using function pointers, as shown in code above.
Regarding the local variables in getOperation (a for example): They are accessed from add/sub/nop using rbp register.
HINT: Compile a small code having 'local functions' with gcc -S, to understand what's exactly going on.. :-)
Nested function (annonymouse functions) are not a part of the c standard library, there is an extension which can be used.
You may declare global variables and use them throughout your programs also.
Sourav is correct actually, you may declare the function but its scope is limited to main