Example code is as follows, both 'a' are file scope:
1 ...
2 int a;
3 int a;
4 ... // which 'a' is visible?
I know that the two declarations for 'a' are for the same object. But every identifier has a scope, the scopes of the two 'a' should overlap at line 4, which one is visible? If the second 'a' is visible only, does that mean this situation is like the following:
{
int a;
{
int a; // the scope of the first 'a' is hidden
}
}
Thanks
At file-scope, something like
int a;
Is a declaration in the first place. It is also a tentative definition. For the same name you can have as many tentative definitions for the same name as you want iff they are technically (see the link for details) identical.
However, if you add an initialiser:
int a = 0;
You have a (regular) definition. Of these you can only have one for the same name. It must also be identical to all tentative definitions.
The second example is about scope. You can use the same name in different scopes. However, the innermost name will be used if you reference the object. There is no way to access an object with the same name in an outer scope. This is called shadowing and a properly configured compiler (i.e. enable warnings) should warn about it, but allow this.
In general this is bad coding style, because you have to check the scope when you read the code to see the declaration. (that's why the compiler should warn). Note that the inner definition need not even have the same type.
To paraphrase this answer:
In a global scope, what you have written will work fine (it will throw an error in the function scope). That is, say you write the following:
int a;
int a;
int main(...){...}
This will compile fine, but only because neither a is initialized. If you declare something with an assignment multiple times, things will break. Here is an example of this:
int a;
int a; // No problem yet
int a = 10; // a is now initialized
int a = 12; // Error: Redefinition of a
The first two definitions (and the kind you gave) are what are known as tentative definitions. The C spec says that multiple ones of these are treated as redundant. The important thing is that each one has either zero or one definitions with initializations.
Lastly, to answer your question:
...
int a;
int a;
... // which 'a' is visible?
My understanding is that the answer is both, since they are tentative definitions for the same variable.
Related
In this page I cannot understand why Example 3 throws an error:
// CODE 1:
extern int var;
int main(void)
{
var = 10;
return 0;
}
There are several answers mentioning that var inside main is a local variable. But why would it not be a global variable at the same time. This code below works tough:
// CODE 2:
int var; // global
int main(void)
{
var = 10;
return 0;
}
In the case of multiple files...
... the code below works:
// CODE 3:
// File 1
extern int var;
int main(void)
{
print("%d",var);
return 0;
}
----------------
// File 2
var = 4;
... while this one does not:
// CODE 4:
// File 1
extern int var;
int main(void)
{
print("%d",var);
return 0;
}
----------------
// File 2
int func(int a) {
extern int var;
var = 3;
return 0;
}
So I could not find a meaningful explanation to the behavior of the extern keyword. How do you explain/ interpret that keyword? Also what should I change in the codes to make them work as intended?
In C, every definition is a declaration. Some declarations are definitions, and some are not.
The page you link to, has mistakes. One is it says that “Declaration of a variable or function simply declares that the variable or function exists somewhere in the program, but the memory is not allocated for them.” Actually, that is two mistakes, at least. Per C 2018 6.7 5, “A declaration specifies the interpretation and attributes of a set of identifiers…” This does not necessarily mean any object or function with the declared name actually exists in the program. For example, if we include the <stdio.h> header, the fputc function is declared, but, if we never use it, it might never be linked into the program, and so no such function might exist in the program, even in the file executable file. A declaration that is not a definition only tells the compiler about the name (which we call the identifier); it does not convey information about whether something exists.
A second mistake in that sentence is that it says memory is not allocated for the declared variable or function. This is incorrect because each definition is a declaration. C 2018 6.7 5 continues “… A definition of an identifier is a declaration for that identifier that: — for an object, causes storage to be reserved for that object; — for a function, includes the function body…” For example, int x = 3; is a declaration of x, and it is a definition of x, and it causes memory to be allocated for x, but the page you link to says a declaration does not cause memory to be allocated. So the page is wrong.
The rules regarding extern and what is or is not a definition are complicated because C was developed by multiple people doing different things with it. When C was standardized, the committee had to reconcile different practices. As a consequence, there is no single rule for extern.
A note about terminology: A variable is actually two things: an identifier (its name) and an object (the memory that stores a representation of its value).
In your CODE 1, the linked page’s Example 3, extern int var; is a declaration that is not a definition. There is no definition. If an identifier with external linkage is used in an expression, there must be exactly one external definition of it in the program (by C 2018 6.9 5). Since there is no external definition, the linker complains.
There are several answers mentioning that var inside main is a local variable.
If an identifier is declared inside a block, such as the { … } that forms the body of a function, then effects of the declaration are local to that block. If an identifier is declared outside of any function, the effects of the declaration continue through the rest of the file being compiled, except where they are hidden by a nested declaration.
If var is declared outside of any function and before main, and then we use that identifier inside main without declaring it again, that use of var refers to the previous declaration. It does not create or refer to a new local object named var.
But why would it not be a global variable at the same time.
At any one point in source code, an identifier refers to at most one thing.
.. the code below works:
…
// File 2
var = 4
var = 4 is not proper C code because it does not have a semicolon. If it were var = 4;, some compilers might accept this outside a function, but it is archaic. In modern C, it should have a type, such as int var = 4;. That would then be a proper definition of var. If your compiler accepted var = 4; outside a function, you should be aware it is accepting old code, and it would be preferable to use switches to tell the compiler to require modern C code.
Code:
typedef int a; // #1
extern int a; // #2, error
gcc will generate an error "'a' redeclared as a different kind of symbol", but when we move the extern declaration to block scope, there will be no warning, why?
typedef int a; // #3
void foo() {
extern int a; // #4, ok
}
And:
char a; // #5
void foo() {
extern int a; // #6, error
}
Update:
Thanks for #Yunnosch's reply, but it still can not answer my question. Let's look at #6,#5, when the compiler sees #6, it will try to lookup in the file scope identifiers to find if the same 'a' exists, although they are in different scopes, the compiler generates an error.
Then looking at #4,#3, when the compiler sees #4, it will find the same 'a' exists in the same way, why doesn't it generate an error?
#Yunnosch and #Stargateur both explain it something about different scopes, it's obviously not true. My view is it's something about linkage, but #2 cannot hide #1 telling me it's also not true.
Update 2:
Thanks for #AnT, he gave a very detailed explanation.
Both typedef names and variable names are ordinary identifiers in C. They share the same name space. You can't have two identically-named declarations that declare different entities in the same scope and the same name space
6.2.1 Scopes of identifiers
2 [...] Different entities designated
by the same identifier either have different scopes, or are in different name spaces.[...]
Also, as suggested by Stefan Ram in comp.lang.c 6.7/3 might be even more relevant here
6.7 Declarations
3 If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:
— a typedef name may be redefined to denote the same type as it currently does,
provided that type is not a variably modified type;
— tags may be redeclared as specified in 6.7.2.3.
In either case, the key point is that both of your declarations are made in same scope and same name space. This is the requirement(s) that is(are) violated by your first code sample. This is what the compiler is complaining about.
Your second and third code samples declare two identifiers a in different scopes. There's no violation of 6.2.1/2 there. These examples might suffer from other issues, but that's a completely different story.
Your second example might be perfectly valid, provided you define the global a in a different translation unit (in a different file scope), where its definition won't conflict with the typedef declaration.
Your third example leads to undefined behavior, since external definition of a specifies a type that is not compatible with the local extern declaration.
6.2.7 Compatible type and composite type
2 All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
If a file-scope object or a function does not need to be visible outside of the file, it should be hidden by being declared as static. This practice creates more modular code and limits pollution of the global name space.
C compilers do not like to see conflicting symbol definitions within a scope,
but do not mind if a conflict occurs only across different scopes.
For example, exaggerating by even using the same kind of symbol:
example 1: basic, warning free, error free
#include <stdio.h>
int a=0;
int main()
{
printf("%d\n", a);
return 0;
}
example 2: conflict same scope
#include <stdio.h>
int a=0;
int a=5; // main.c 3 error: redefinition of 'a'
int main()
{
printf("%d\n", a);
return 0;
}
example 3: different scopes conflict free
#include <stdio.h>
int a=0;
int main()
{
{
int a=5;
printf("%d\n", a);
}
printf("%d\n", a);
return 0;
}
In example 3, the "inner" a, with value 5, hides the outer a.
The value 5 is happily printed from withing the inner scope, it hides the outer a.
Then, when the inner scope is left, the outer value 0 is happily printed. It is not hidden by the inner scope anymore.
In your 1st case, the conflict arises between two as (in your case of different types), when they are in same scope, like in my example 2.
In your 2nd case, the two as are in two different scopes and do not conflict.
My example 3 shows, that in that case they would not even conflict if they were the same type AND same identifier.
example 4: conflicting types between global and extern local
(swapped types, to continue the example sequence)
#include <stdio.h>
int a=0;
int b=1;
static int c=10;
void foo() {
extern int b;
extern char a; // main.c 8 error: conflicting types for 'a'
extern char c; // main.c 9 error: conflicting types for 'c'
}
int main()
{
{
int a=5;
printf("%d\n", a);
}
printf("%d\n", a);
return 0;
}
In example 4, based on your question-edit, the extern tells the compiler to use an a which has been defined elsewhere, explicitly telling it to use it in this function scope, too.
The compiler has however already seen a definition of a and (assuming it is the only one, because it would otherwise be a redefinition) it complains about the different types. Note the different error, "conflicting types" instead of "redefinition".
In contrast to that, note that the similar line above, with b, does not conflict. The compiler is told to know about a b, to be found elsewhere, with identical type. That is found in the outer global scope.
Using static, to make a symbol file-only scope insteadd of global, does not change this, the example uses c to demonstrate. The external c is still identified to be the conflicting c with different type, defined at this files scope.
I am new to C and I experience some confusion between the declaration and definition of a variable. Another thing I would like to know is if the following is true:
"Declaration appears many times and definition comes once."
Also:
int x;
Is this a declaration only? Since memory is allocated for x then why isn't this a definition instead of a declaration?
Simply writing int x; at either global scope or local scope, is both a declaration and definition. Typically, the declaration tells the compiler "This variable will exist, at some point, under this name, so you can use it." The definition tells the compiler to actually arrange for the variable to be created - obviously this can only happen once.
Typically the way you'll use this is by putting in a header file:
// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined
extern int bar; // Declare a variable bar
#endif
And in a single source file
#include "foo.h"
int bar; // Define bar
If you were to define bar in multiple files, you would get an error; you can't create the variable twice. But you do have to tell the compiler about it in every source file you use bar in. Hence the extern declaration.
The precise semantics are defined in §6.9.2 of the C standard and can be summarized as follows:
When a variable is declared at file scope with an initializer, it is an external definition. (§6.9.2/1)
When a variable is declared at file scope without an initializer, and without a storage-class specifier or with the static storage-class specifier, it is a tentative definition. If the translation unit (file) has one or more tentative definitions and no external definition, the compiler automatically adds a true file scope declaration at the end of the translation unit, with a zero initializer. (§6.9.2/2)
What this means is that, strictly speaking, int x; is not a definition; but it automatically creates a definition if and only if there is no other definition with an initializer, and no static definition (this third case is undefined behavior due to linkage disagreement per §6.2.2/7)
Note that extern int x; is not an external definition. It is a declaration with an extern storage class specifier. As such, extern int x; alone does not cause a definition to be created, but if you have both:
extern int x;
int x;
Then you will end up having a definition created at some point in the file.
It is also, technically speaking, legal to do this:
extern int x;
int x;
int x = 42;
In this case, the int x; in the middle is superfluous and has no effect. That said, this is poor form, as it's confusing in this case where the actual definition is.
This isn't something you see too much in C, but it works like this:
In a header file, you can have a line like this:
extern int x; //declaration
Because of the extern modifier, this tells the compiler that there is an int named x somewhere. The compiler doesn't allocate space for it - it just adds int x to the list of variables you can use. It'll only allocate space for x when it sees a line like this:
int x; //definition
You can see that because only the int x; line changes your executable, you can have as many extern int x; lines as you feel like. As long as there's only int x; line, everything will work like you want it to - having multiple declarations doesn't change a thing.
A better example comes from C++ (sorry if this is a C-only question - this applies to structs as well, but I don't know the syntax off the top of my head):
class Pineapple; //declaration
Pineapple* ptr; //this works
Pineapple pine; //this DOES NOT work
This declaration tells the compiler that there's a class called "Pineapple". It doesn't tell us anything about the class (how big it is, what its members are). We can use pointers to Pineapples now, but we can't yet have instances - we don't know what makes up a Pineapple, so we don't know how much space an instance takes up.
class Pineapple
{
public:
int ounces;
char* name;
}; //definition
Pineapple* ptr; //still works
Pineapple pine; //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;
After a definition, we know everything about the class, so we can have instances, too. And like the C example, you can have multiple declarations, but only one definition.
Hope this helps!
Content of X.c:
int i;
main ()
{
fun ();
}
Content of Y.c:
int i;
fun ()
{
}
Why does these two files compile with no error ? (using GCC)
But if i use int i = 10; it prints a multiple definition error.
You may be interested in this question and the answers. Keywords: "tentative definition".
Tentative definitions in C99 and linking
Assuming you really want an independent variable called i in each of these two files, you need to prefix them with static in order to give them internal linkage.
static int i = 10;
If you want i to be the same variable in both files, so changes in one affect the other, use the answers you were given 3 hours ago when you asked a variant of the question. If it is to be shared, you need to define the variable in one place.
As to why it didn't cause an error without the init, I think that's because you weren't using the variable until it needed initializing and so the compiler ignored it.
Because there is a difference between a declaration and a definition. int i; does nothing more than introducing a name. int i = 10; on the other hand defines i, hence, a place in the memory must be reserved to store the value it corresponds to. But it is impossible for the compiler to know which value corresponds to i as you want to associate two memory locations with the name i.
This is under the assumption that you link these files against eachother, which is not entirely clear from your explanation.
I've faced three separate situations in C lately that I would assistance on:
My C code has a global variable:
int ref_buf; //declared in a header file
In a function definition I use the same name as a parameter:
void fun(int ref_buf, param2, param3)
{
}
Will it overwrite the originally defined global variable and will it cause bugs?
Can I declare a static variable in a C data structure like so?:
struct my
{
int a;
static int b;
};
Does it work? Is there any specific situation where one would need it?
Can I initialize a individual structure variable as follows:
struct my
{
int a;
int b = 4;
};
Question 1
All references to ref_buf in that function will bind to the parameter and not the global variable.
Question 2
This is not legal in C but is legal in C++. The keyword static in C can only be used on file scope variables or on locals.
Question 3
No this is not legal in C (or C++). You will need to create a factory method to handle this.
my create_my() {
my m;
m.b = 4;
return m;
}
On Q3: GCC allows you to initialize a struct like this (as required by the C99 standard):
struct
{
int a;
int b;
} my = { .b = 4 };
GCC doc on designated initializers
1a) The local and global variables are separate entities, and so the local one won't overwrite the global. However, the global one won't be accessible inside the function (see also notes below).
1b) It not actually incorrect, but it is guaranteed to cause confusion, and confusion causes bugs, so it's best to use different names for each.
2) No, that's not legal C. You can however make the whole struct static.
3) No. You do it like this:
struct my
{
int a;
int b;
} = {0, 4};
Note 1: Variables should be declared in .c files, not .h files. If you need to make a variable accessible in multiple files, put an extern declaration in the header file.
Note 2: Avoid global variables if at all possible.
Question 1:
I think the variable declared in the local scope takes precidence, it shouldn't overwrite it but in the scope that the variable is declared it will be used instead.
That is assuming that it compiles.
On Q1:
Do not declare variables in a header file. If you include that header file in two source files and compile the source files together, you've got problems. Maybe your linker will get you out of them, maybe not.
If you really need global variables, and this happens a lot less than typical beginners think, put something like extern int ref_buf; in the header file, and int ref_buf; in a source file. That means there is one ref_buf, and all other source files will be able to find it.
The function parameter is essentially a new variable with the same name, and all references in the function will be to it. You will not be able to access the global variable from within that function. The function creates an inner scope, and variables declared in an inner scope are different from those in an outer one. This is potentially confusing, and makes it easy to create bugs, so having variables of the same name and different scopes is generally discouraged. (Variables of the same name in different struct definitions are usually not confusing, since you have to specify what struct contains the variable.)
The compiler will compile the function, but a good compiler will issue a warning message. If it refuses to compile because of one variable shadowing another of the same name, it isn't a real C compiler.
1) Local variables always take precedence e.g.
int ref = 10;
void fun(int ref)
{
printf("\n%d\n", ref);
}
int main()
{
fun(252);
return 0;
}
shows: 252
Qs 2 and 3 won't work in C.
Yes, it will technically overwrite, but a good compiler will warn you about this situation, and you will have "warnings = errors" on when you compile, so this won't actually compile.
Not needed, since the "my" struct is already declared as static, and it is therefore declared for the entire struct. This allocates the memory for the entire struct, so there is no need to say "take part of the struct which is already static and make it static".
No, not in the definition, but you can when you create an "instance", something like:
struct my MY =
{
{0, 4}
};