Duplicated identifier for a variable in function local scope - c

So, this is code from a student of my friend…
#include <stdio.h>
int main(){
int hours;
int take_one_number(void);{
scanf("%d",&hours);
}
int minutes;
int take_one_number(void);{
scanf("%d",&minutes);
}
int seconds;
int take_one_number(void);{
scanf("%d",&seconds);
}
int all;
printf("%d",all=hours*3600+minutes*60+seconds);
return all;
}
Well, it… compiles… and… uhm, works… as requested by the teacher…
My question: if I understand correctly, take_one_number here is a definition of a variable to store a function pointer. Why does neither GCC nor LLVM complain about a duplicated identifier in these definitions?

The function take_one_number is declared 3 times, but never defined. In each case, the ; after the (void) ends the declaration. The scanf statement is then just a regular statement inside of main(), surrounded by a meaningless scope { }

In the above code ,
int take_one_number (void);
is not a function pointer , it is function prototype or declaration , a function can be declared more than once , but must be defined only once.

int take_one_number(void);
It's a function declaration whose return type is int. It's not a definition of a variable. And the scoping you did for variables has little meaning here as no variable declaration is happening in it.

int take_one_number(void); is a function prototype to tell the compiler that there is a function implemented somewhere with this name and property. Compiler does not complain because you are neither defining new function nor using that function.
You should also note that the blocks that follow after this prototype are not part of the take_one_number as they are separated with semi-colon. Making the blocks as independent scope blocks. To make things more clearer there would be compilation error if there were no semi-colon between the function prototype and the code block next to it.

Related

A function's prototype is similar to declaring the function in the calling routine?

If there is no function prototype, a function is implicitly declared by its first appearance in an expression.
In C, if a function return anything else than int it is a good habit to declare the function inside the caller function like 1st example of code.
But you are always constrained by the compiler to write the prototype, the reason is that he does not know who the function is because it is declared underneath the main() function.
The question is: These two are equivalent? Will either writing the prototype or declaring explicitly the function inside the main() return the wanted result? How can it return a bad value if you are constrained always to use one of this two ways?
if the function is declared in the same script as the caller function is (here main())
prototype
declare explicitly function in main().
if the function is declared in another file
prototype
declare explicitly function in main()
E.g:
int main()
{
double doSomething(int a);
printf("%d", doSomething(2) );
}
double doSomething(int a)
{
return a * 2.0;
}
vs
double doSomething(int a);
int main()
{
printf("%d", doSomething(2) );
}
double doSomething(int a)
{
return a * 2.0;
}
This thread is almost what i needed but it did not answer all my questions.
C language - calling functions without function prototype
These two declarations are equivalent until in the first case the function doSomething will be required in some other function except main.
In this code snippet
int main()
{
double doSomething(int a);
//..
there is a function prototype of the function doSomething.
From the C Standard
A function prototype is a declaration of a function that declares the
types of its parameters
That is before the function definition that is also its declaration the name of the function will be visible only in the block scope of main.
Consider the following program
#include <stdio.h>
void g( void )
{
f( 20 );
}
int main(void)
{
void f( int );
f( 10 );
return 0;
}
void f( int x )
{
printf( "x = %d\n", x );
}
The compiler will issue an error for this statement
f( 20 );
because the name f is not yet declared.
But this statement
f( 10 );
is correct because the name inside the block scope of main is already declared.
To make it more clear take into account that functions always has a linkage opposite to variables declared in a block scope without a storage class specifier.
So this declaration in main
double doSomething(int a);
is equivalent to the declaration
extern double doSomething(int a);
And the linker will find the function definition even if the function initially is declared in a block scope.
In modern C, you should always declare a function before using it. (That includes defining a function before using it, because a definition is a declaration.) Implicit declaration of functions to return int is a behavior of very old verions of C. It should not be used, compilers should at least warn about it, and you should set your compiler to make it an error, not a warning.
Functions are usually declared outside of other functions. There is nothing explicitly wrong about declaring a function inside another function, but we rarely do it because we generally want functions to be visible throughout a translation unit, not just in one specific place. (A translation unit is one source file together with all the files it includes via #include directives.) The names of functions obey the same scope rules as object names: If it appears outside of any function, it has file scope. If it appears inside a block (a list of statements inside braces, { … }, which includes function bodies), it has block scope and is only visible in that block.
Whether a function is declared at file scope or block scope will not affect how it behaves.
main is not special in this regard. You are likely asking about main because you are early in your programming education, and you mostly call functions just from main. However, functions may be called from other functions, and the rules about scope and name visibility are not particular to main. If a function is declared at file scope, its name is visible throughout the rest of the translation unit. If a function is declared at block scope, whether inside main or another function, its name is visible throughout the rest of that block.
If a function is defined to return double but you use it without declaring it, and your compiler allows that, then you can expect your program to work incorrectly. The compiler will not automatically convert double to int. The function type is important to tell the compiler what the function returns because the compiler expects certain bits to be in certain places when the function returns, and it writes instructions relying on that.

How are we allowed to use a forward-declared object or function, and how are we not?

If we declare an object or function without defining it, how are we allowed to use it before its declaration and how are we not allowed to use it before its declaration ? (For a similar question using a forwarded declared structure tag before its definition, basically how we are allowed to use an incomplete type and how not, see https://stackoverflow.com/a/45725061/3284469)
Does it matter if the declaration appears in file scope or block scope?
Does it matter if its definition appears in the same or a different translation unit?
For example
extern int i;
(what can we do with i here?)
(what can't we do with i here?)
int A = i+3; // error: initializer element is not constant. This is an error not due to forward declaration of int i
int i = 3;
void fun();
(what can we do with fun here?)
(what can't we do with fun here?)
void fun(){};
Declaring an object is a promise to provide a definition at some other place. Once you declare a function or an external variable, from that point on you are allowed to do anything that you would be allowed to do to a function or a variable that you have defined.
The scope of the declaration has no effect on what you can do, only on the location in code where you can do it.
In most cases, code translator requires all external references to be satisfied at the time the code is linked. Otherwise, you get a linking error.
One exception to this rule is using declared object in a sizeof expression, which does not require an access to underlying object:
extern int undefined;
size_t res = sizeof(undefined);
The above will not break a link, because sizeof expression does not generate access to its arguments.
You can do anything with the declaration except for inlining it. For example:
void fun();
inline void fun(){}
After the declaration you can call the function, unless the definition is marked inline in which case it will result in a linker error because the definition does not emit a symbol to link against. Even if you don't say inline explicitly, an optimizing compiler may inline calls to the function if the definition has been seen.
www.cprogramming.com say's:
When you declare a variable, a function, or even a class all you are
doing is saying: there is something with this name, and it has this
type. The compiler can then handle most (but not all) uses of that
name without needing the full definition of that name. Declaring a
value--without defining it--allows you to write code that the compiler
can understand without having to put all of the details. This is
particularly useful if you are working with multiple source files, and
you need to use a function in multiple files. You don't want to put
the body of the function in multiple files, but you do need to provide
a declaration for it.
extern int i;
Here, an integer type variable i has been declared (but no definition i.e. no memory allocation for variable i so far). And we can do this declaration as many times as needed.
void fun();
Function fun() declare, but not defined. but it does tell the compiler that it can use this function and expect that it will be defined somewhere.
what can we do with i here
With
extern int i;
i can be declared as many times as required in the program.
You can have an initializer
extern int i = 0;
what can't we do with i here?
You can't use i without defining it in the program.
extern int i;
int main(void)
{
i = 10; // Will through an error
return 0;
}
In case of function this keyword only tells that the linkage for the function is extern. By default linkage of a function declaration/definition is extern.

How are extern variables defined?

I have a few doubts regarding the use of extern keyword with variables in C. I did go through the links related to this question. However, there are still a few things that I didn't gather very well
#include<stdio.h>
main( )
{
extern int i;
printf ( "\n%d ",i) ) ;
}
int i = 31 ;
In the above code, how does I get printed before its definition statement?
Now in the following code:
#include<stdio.h>
int x = 21 ;
main( )
{extern int i;
i=20;
printf ( "\n%d ", i ) ;
}
Isn't the statement "i=20;" a definition statement? I get an error for this. Is it because i'm trying to change the variable that is defined in some other source file? If this is the case how is the statement "int i=31;" in the top most code snippet right to use?
Also, I read, "int i;" is a definition. I don't really follow how.
In your first program, the print statement is printing the value of i based on the extern int i declaration. This is similar to calling a function based on its prototype declaration without seeing its definition. The compiler generates code to retrieve the value in the global variable named i. The symbol is resolved to the correct variable and address at link time.
In your second program, no definition for i is provided, only the extern int i declaration, and the attempt to set its value with i = 20. At link time this fails, since there is no definition, and so the attempt to resolve the reference to the global variable fails. Changing i = 20 to int i = 20 instead creates a local variable named i within the scope of the function main(), and is no longer referencing the globally declared extern int i.
When int i; is used at global scope, it is treated as a declaration and may be treated as a kind of definition. A global variable declared with an initializer, like:
int i = 20;
is always treated as a definition. Only one definition of this type is allowed, even if each is using the same initializer value. However,
int i;
is treated like a declaration. If more than one of these declarations appear, they are all treated as declarations of the same variable. At the same time, if no declaration with an initializer is present, this variable is implicitly defined with an initializer of 0, and the linker will be able to resolve references to it.
Declaration of a variable/function simply declares that the variable/function exists somewhere in the program but the memory is not allocated for them.
Coming to the definition, when we define a variable/function, apart from the role of declaration, it also allocates memory for that variable/function.
So in the 1st program, int i = 31 outside the main() defines the variable i. This variable is then merely declared as an extern variable inside the main(). Hence the program works.
In the 2nd program, without defining the variable i elsewhere, it is directly declared as an extern variable. Hence it gives an error.
In the second program you haven't defined the variable anywhere , not outside the main and instead you have defined it inside main so you are getting that error.
But in the first program you are defining the variable once and that is outside the main so you don't get that error.Program looks outside the main and find its definition.
int i; is a variable definition declaration both for AUTO variables (i.e inside main or any function ) but not for the external variables for extern variables you have to declare it like :
extern int i;
and then define outside main like this :
int i;
The idea behind extern is that you tell the compiler you're going to use a variable that was already defined outside the scope of where it is used.
It doesn't make much sense in your second case as there i is defined as a local variable.
If you were to define it as a global, like you do in the first case, it would be fine.
If I can demonstrate the use of extern with a very simple (contrived) case:
main.c:
#include <stdio.h>
extern int a; /* we tell the compiler that a will come from outside the scope of where it is used */
int main()
{
printf("%d\n", a);
return 0;
}
source.c:
int a = 3; /* we define a here */
You then compile both .c files like this:
$ gcc main.c source.c
This outputs 3.
You might also want to have a read at this article.

extern variables in C and their scope

I am trying to understand this code:
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
When I run it, the value of a is 20. Yet this should be impossible, since the global variable a is defined at the bottom.
An extern declaration can only be used with variables that are global. It tells the compiler that the global variable is defined elsewhere, and asks the linker to figure it out.
In your code, extern int a refers to the a defined at the bottom of your example. It could have been equally well defined in a different translation unit.
As others have pointed out, the initialization of a takes place before main() is entered.
Not a problem. By declaring the variable as extern you are promising the linker it is defined else where part of current or other source files at global scope.
Initialization of global variables occurs before main() is called.
So even if the initialization a = 20 is located beneath the implementation of main(), it's always executed first, so it can be used at program start (assuming you fittingly declared the variable in scopes where it's to be used using extern int a).

Can we use main, printf,scanf for naming identifiers?

int main()
{
int main=5;
printf("%d",main);
return 0;
}
In this case there is no error and the gcc compiler prints 5. But if I write
int main()
{
int printf=5;
printf("%d",printf);
return 0;
}
the compiler shows an error..why ?
In your 1st example you "hide" the main function, replacing it with an int object.
In your 2nd example you "hide" the printf function, replacing it with an int object.
Trying to call an int is illegal.
5("foo"); /* illegal to call "function" 5 */
In your first code snippet, you declare a local variable main, which is in the local scope, so it has no effect on the global scope (where the main() function is declared)
In the second code snippet, you declare "printf" in global scope, where the printf() function lives, so you have a conflict.
In the second example, you have declared a local variable of type 'int' called 'printf'. This will take precedence over the global function of the same name. So the error is that the name 'printf' refers to an int, not a function.
In your first example, you override the global function name 'main' with a local variable called 'main'. If you had not done that, you would in fact be able to call the 'main' function from within the main function, and that would have worked. With your variable declaration, that is no longer possible as the local variable declaration takes precedence - but it's still perfectly usable in the variable form.
You shouldn't use function names as variable names, ever, for any reason.

Resources