What is the meaning of "each undeclared identifier is reported only once for each function it appears in error"? - c

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.

Related

Why is a variable that is declared globally and initialized in main (or any function) accessible to other functions? In C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last month.
Improve this question
I'm new to programming and want to know more about why this is possible. Here's an example of what I'm talking about.
#include<stdio.h>
int x;
void add_x(int y);
int main(void)
{
int y;
x = 1;
y = 2;
add_x(y);
}
void add_x(int y)
{
int z;
z = x + 2;
printf("%i\n", z);
}
Above prints out 3.
And why is it that if I say x = 4 inside the add_x function will the answer be 6 and not the 3? In other words why does the function use its x variable instead of the global x.
Visibility rules for identifiers, also known as "scope" rules, are discussed in detail here. Storage duration (i.e the the lifetime of an identifier) is related to scope and is covered here. I encourage the reader to have a look and spend some time with the sample code available there.
In the example provided by the OP, the variable x is defined outside any block or function and has therefore static storage (it lasts for the entire duration of the program) and external linkage (can be referred to by any other function in the program). The assignment x=1; in main() implies that x has value 1 from that moment onwards. Hence the value 3 produced by add_x().
If we slightly modify the original code, as follows
#include<stdio.h>
int x;
void add_x(int y);
int main(void)
{
int y;
x = 1; // Now it's 1, but will be set to 12 in add_x()
y = 2;
add_x(y); // this call sets x to 12.
}
void add_x(int y)
{
int z;
x = 12; // We assign a new value to x
z = x + 2; // result is 14
printf("%i\n", z);
}
the result of add_x() is now 14 and x will maintain the value 12 from the moment of the assignment until the end of the program.
If we define a new identifier x in the function add_x(), as showcased below, the new identifier will have limited scope and duration, i.e it will be seen only within the add_x() function (it will "shadow" the global x defined outside the function) and will stop existing as soon as the add_x() returns. Crucially, the output of add_x() will change accordingly but the value of the x defined outside the function will stay untouched:
#include<stdio.h>
int x;
void add_x(int y);
int main(void)
{
int y;
x = 1; // x will retain its value throughout the program
y = 2;
add_x(y); // prints 24 due to the new x defined in add_x()
}
void add_x(int y)
{
int z;
int x = 22; // we declare and inizialize a new x
z = x + 2; // the result is now 24
printf("%i\n", z);
} // the x we declared and inizialized in add_x stops existing here
That is because your value is declared globally so you can access it from every function. That is, its value can be set or retrieved from anywhere.
This is not the case for local variables. For example if you declare a variable in main and try to access it by name from another function that is an error.

Comma operator with undeclared variable - why does it compile?

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.

Do cycles have their own stack record? (aka why is this code legal)

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.

C: why do I get invalid initializer?

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;
}

Declaring a variable in C

I’m having a hard time with declaring my variables within C. The compiler display a message “expected constructor destructor or type conversion before token.” What am I doing wrong?
#include <stdio.h>
int count =0;
int abc;
ABC;
a = 19, b = 27, c = 3;
a = 4 + 5 * 3;
b = (4 +5) * 3;
c = 25 -(2 * (10 + (8 / 2)));
main {
printf("Enter a value please\n");
scanf("%d, , \n");
return 0;
}
Here's a rewrite, showing how to fix the various issues:
#include <stdio.h>
int count = 0; // declarations and intitializations are allowed at file
// scope (that is, outside of any function body). The
// storage for count will be set aside at program start
// and held until the program terminates.
//
// count is visible to all functions defined within this
// file, and will be visible to other files compiled and
// linked into the same program.
int main( void ) { // Implicit typing of functions is no longer allowed as of C99,
// and it was never good practice to begin with.
// IOW, the compiler will not assume a return type of
// int if a type specifier is missing. main always
// returns int, and either takes 0 or 2 arguments.
int a, b, c; // int abc; declares a *single* variable named "abc",
// not three variables named "a", "b", and "c".
// Storage for these variables will be set aside at
// function entry and held until the function exits.
//
// None of a, b, or c are visible outside of the
// function body.
// ABC has not been defined anywhere; it's not clear
// what the intent was behind ABC;
a = 19; // While not illegal, a = 19, b = 27, c = 3; is not the best style
b = 27; // in the world; it's better to make these three separate statements
c = 3; // Note that assignment statements (like any other executable
// statement) are not allowed outside of a function body.
a = 4 + 5 * 3; // fine
b = (4 +5) * 3; // fine
c = 25 -(2 * (10 + (8 / 2))); // fine
printf("Enter a value please\n"); // fine
scanf("%d", &a); // Each conversion specifier in a scanf call needs a corresponding
// argument to write the input value to, and the argument needs
// to be of the correct type. %d expects the corresponding
// argument to have type "int *" (pointer to int). The expression
// "&a" gives the address of the variable "a", and the type
// of the expression is "int *". So, this statement will read an
// integer value from standard input and store it to a.
return 0;
}
You cannot write assignments like a = 19, b = 27, c = 3; outside functions.
int count = 0; is the initialisation of a global variable, so that is allowed.
ABC; is also meaningless unless ABC has been #defined to something numerical, and even then it would be a no-op.
main is also malformed. You need to write it as int main() and make sure you return a value.
Lastly, your scanf argument list is not correct. Do consult the documentation.
It would be a good idea to study an introduction to C. Kernighan & Ritchie is an excellent book.

Resources