Why does this code not throw a compilation error for y being undeclared?
int x = 10, y;
printf("%d", y);
There's no expression like int y;. In my case, the console print out is 32764, which seems to just be uninitialized memory. Looking at the assembly code for the first line, it's the same whether the , y is there or not, even if y is used in the print statement.
Expected to see
error: use of undeclared identifier 'y' printf("%d", y);
This:
int x = 10, y;
Is not an instance of the comma operator. The , is part of the grammar of a declaration which allows multiple variables to be declared on the same line. Specifically, it declares x and initializes it to 10 and declares y which is uninitialized. It's equivalent to:
int x = 10;
int y;
Had you instead done this:
int x = (10, y);
Then you would have an instance of the comma operator and an error for an undeclared identifier.
Related
I know that multiple variables belonging to same data type can be declared in one statement as below:
int x, y, z;
I tried to declare and define multiple variables belonging to same data-type in one statement as below :
#include <stdio.h>
int main() {
int x = y = z = 50;
printf("%d", x + y + z);
return 0;
}
When I tried to compile above code I got following errors:
prog.c: In function ‘main’:
prog.c:4:11: error: ‘y’ undeclared (first use in this function)
4 | int x = y = z = 50;
| ^
prog.c:4:11: note: each undeclared identifier is reported only once for each function it appears in
prog.c:4:15: error: ‘z’ undeclared (first use in this function)
4 | int x = y = z = 50;
| ^
I don't understand why multiple variables belonging to same data type cannot be initialized to the same value in a single statement, whereas it is possible to declare multiple variables belonging to same data type.
I also don't understand the actual meaning of the note "each undeclared identifier is reported only once for each function it appears in." Why is it appearing?
Though, when I tried below code where I created two statements for variable declaration and definition separately everything worked smoothly. Why so?
#include <stdio.h>
int main() {
int x, y, z;
x = y = z = 50;
printf("%d", x + y + z);
return 0;
}
And got expected below output:
150
int x = y = z = 50;
The assignment = operator has right-to-left associativity. The above statement first tries to assign 50 to z, but as it was never declared, it generated an error.
I don't understand why multiple variables belonging to same data type
cannot be initialized to the same value in a single statement, whereas
it is possible to declare multiple variables belonging to same data
type.
Actually you can, but only if they are declared first. In this case, you didn't declare y and z before initializing them.
What you're looking for is:
1) int x = 50, y = 50, z = 50;
/* OR */
2) int x, y, z;
x = y = z = 50;
/* Or */
3) int x = 50;
int y = 50;
int z = 50;
/* Or */
4) int x, y, z = x = y = 50; /* This is madness. */
I find that declaring one variable per line (the 3rd approach) makes the code clearer and prevents asinine mistakes when declaring pointers.
I also don't understand the actual meaning of the note "each
undeclared identifier is reported only once for each function it
appears in." Why is it appearing?
It means that the compiler will only report the first instance of an undeclared variable in a given function. For instance, if you have:
int x = y = z = 50; /* Compiler only reports this instance */
z = 403;
The compiler will only report the first time z appears.
You can cut it into pieces like this :
int x=y
This is an initialization, you're telling the computer that i need an integer named x, that's equal to y, but this y is undeclared, because you're using it as a value to initialize with, not declaring it.
Then we go to y=z
Now you're trying to assign an undeclared variable y, with another undeclared variable z.
Then z=50;
This is an assignment, and z was never declared, this is its first appearance in the function.
int will be casted on the first variable to the left, and the first variable after every comma if available. Every variable after that will be considered as an already declared variable.
Your second piece of code works because the compiler already knows about each variable you declared, so there's no problem there.
Ok, so I'm having a little question for you here.
I'm going to write code in C, but I guess this would work just the same in most languages.
So, why is this code legal:
int x = 1;
while(true) {
int x = x + 2;
}
While this calls for error: redefinition of ‘x’
int x = 1;
int x = 3;
So, I am aware that I'd be able to use the same name for a variabile in different functions within my program, since each function call would have its own stack record.
But do cycles have their own stack records as well? On a memory level, code #1 doesn't result in me having N different associactions for the variable x within the same stack record block?
In short, why in code #2 I'm redefining the x variable, but in code #1 I am not?
The two variables are declared in different scope.
int x = 1;
while(true) {
int x = x + 2;
}
The variable declared in the inner scope hides the variable declared in the outer scope.
Pay attention to that this declaration
int x = x + 2;
has undefined behavior because the declared variable is used itself as an initializer though it was not initialized.
For example you can write
int x = 1;
int main( void )
{
int x = 2;
while ( 1 )
{
int x = 3;
/*...*/
}
}
In this program there are declared and defined three different objects with the name x.
The first variable has the file scope while the other two have block scopes.
As for this code snippet
int x = 1;
int x = 3;
two variables in the same scope are defined with the same name.
In C (but not in C++) you may write
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
return 0;
}
because in the file scope this
int x;
is not a definition of the variable x but is only its declaration.
Also you may write for example
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
extern int x;
printf( "x = %d\n", x );
return 0;
}
The line
extern int x;
introduces the declaration of the global variable x in the block scope of main.
As for the while statement then (The C STandard, 6.8.5 Iteration statements
)
5 An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.
I have to do a function which returns the dot product of two vectors.
Here his the code:
float res;
float v1[3];
float v2[3];
v1[0] = 3;
v1[1] = 2;
v1[2] = 0;
v2[0] = 2;
v2[1] = 5;
v2[2] = 0;
float dotProd(float *vec1, float *vec2) {
return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2];
}
res = dotProd(v1, v2)
I thik the function is right, the problem is that I get invalid initializer error when I define the values of the vectors.
What am I missing?
What you are attempting to do is not initialization but assignment. The former is done at the time the variable is defined, while the later is done later as an executable statement. You're getting an error because executable statements are not allowed outside of a function.
You need to use an initializer at the time the arrays are defined:
float v1[3] = {3, 2, 0};
float v2[3] = {2, 5, 0};
float v1[3];
// ...
v1[0] = 3;
v1[1] = 2;
v1[2] = 0;
This: float v1[3]; is a declaration (and a definition). It defines an array object named v1. It can legally appear either at file scope (outside any function) or at block scope (inside a function definition).
This: v1[0] = 3; is a statement. Statements are permitted only inside a function definition.
If you want those statements to be executed just once, you can put them inside your main function.
Execution of your program begins with an implicit call to your main function. Very nearly everything that happens as your program runs results from that, as other functions are called from main, directly or indirectly. If you could have statements outside any function, there would be no way for them ever to be executed. File-scope declarations are permitted, but they're restricted to ones that don't execute any code. For example, a declaration like:
int n = 42;
is permitted either at file scope or at block scope; if it's at file scope the value 42 is loaded into n at program startup. But if the initializer isn't a constant expression, such as:
int r = rand();
then it can only appear at block scope; there's no way to call a function before main starts.
As for why you're getting that particular message, the compiler's parser isn't expecting to see a statement in that context, so it tries (and fails) to interpret v1[0] = 3; as a declaration. When a compiler sees something that's syntactically invalid, it tries to interpret it in a way that lets it give a meaningful error message, but it doesn't always succeed.
Your code is fine; you are probably just having a structure problem.
Try something like:
#include<stdio.h>
float dotProd(float * vec1, float * vec2) {
return vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2];
}
int main() {
float res;
float v1[3];
float v2[3];
v1[0] = 3;
v1[1] = 2;
v1[2] = 0;
v2[0] = 2;
v2[1] = 5;
v2[2] = 0;
res = dotProd(v1, v2);
printf("%lf", res);
return 0;
}
Why is this code allowed in C?
int x;
int main() {
printf("%d\n", x);
return 0;
}
int x = 2;
It compiles without warnings using -Wall -std=c89 with both gcc and clang.
I have previously thought that int x at global scope is equivalent to int x = 0. I find myself surprised.
int x;, at file scope, is a tentative definition as well answered by #PSkocik and will act like int x = 0; if a definition with initialization does not exist.
I have previously thought that int x at global scope is equivalent to int x = 0.
The tricky part about a "global" int x; is assuming it is initialized with 0. It is initialized with 0 if another int x = constant; does not exist in any compilation unit.
Therefore recommend explicit initialization and not counting on default initialization to 0 bits when the object needs initialization.
// Does an initialization exist, in some file -maybe?
int x;
// Better. If another file initializes `x`, good to see a compiler/linker error.
int x = 0;
int x;
Is a declaration.
int x = 2;
Is a definition (which is also a declaration).
Re-declaration is allowed as long as the declarations are compatible (the same).
int x;
int x;
Will work. Re-definition is not allowed
int x = 2;
int x = 2;
Will not work.
Use without a declaration before it or without a definition is disallowed
I use only C99, and, yesterday, I heard that it was impossible to mix several declarations and initializations in ANSI C. Thus, codes like this :
unsigned x = 42, y = 21;
double e = 3.14;
Would be, with gcc' -pedantic flag :
unsigned x, y;
double e;
x = 42, y = 21;
e = 3.14;
I'm surprised, because I didn't find any information about that in C89 draft, and a code like this works fine...
unsigned x = 42, y = 21;
double e = 3.14;
Sorry, it seems to be a trivial question, but I did some research, and nothing told me about this rule...
Is it true ?
An initialization is a part of declaration, so you can do initialization in a declaration in both C89/C99:
/* Valid in C89 and C99. There are no statement, only declarations */
unsigned x = 42, y = 21;
double e = 3.14;
What you cannot do is to mix statements and declarations in C89:
/* Not valid in C89, valid in C99: mixing declarations and statements */
unsigned x, y;
x = 42, y = 21;
double e;
e = 3.14;
Actually, I'm using your first syntax with -pedantic flag and it works well, without any warning.
As far as I know, you can't mix your code like this:
int i;
i = 2;
int j;
j = 2;
This is because, in C semantic, every program is a block and a block is a couple [declarations, commands]. But declaration include initialization of variables as well.
Every time you open a new block, for example with a while or an if, you'll have a second block, and again you can have a declaration part, and a command one.