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.
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.
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
This question already has answers here:
C function syntax, parameter types declared after parameter list
(7 answers)
Closed 2 years ago.
I stumpled upon a C code, where variables seem to be declared after the argument list of a function. I did not know that this was possible.
In the code, int r and int *a are declared right after the argument list of arr2int. How does this affect the local variables a and r of arr2int?
The actual reason why I want to understand the code is because if I let it run on my linux x86 a[1] = 1 at //MARKER when arr2int ist called the fist time.
But if I let it run ona an ARM-based omap4 dev board a[1]=0 and I dont know why there is a difference.
Could someone comment on this please?
long arr2int(a,r)
int r;
int *a;
{
int i;
long mul, result = 0, temp;
//MARKER
for (i=1; i<=r; i++) {
mul = 1;
temp = a[i]-1;
while (temp--)
mul = mul << 1;
result += mul;
}
return(result);
}
And the calling method:
void generateEncodingTable(){
register int i,j;
long temp;
int seed = 133757;
printf("\n[I] - Generating Encoding Table\n");
for (pattern = 0; pattern < 4096; pattern++) {
temp = pattern << 11; /* multiply information by X^{11} */
encoding_table[pattern] = temp + get_syndrome(temp);/* add redundancy */
}
decoding_table[0] = 0;
decoding_table[1] = 1;
temp = 1;
for (i=2; i<= 23; i++) {
temp *= 2;
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1; a[2] = 2;
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<253; i++) {
nextcomb(23,2,a);
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1; a[2] = 2; a[3] = 3;
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<1771; i++) {
nextcomb(23,3,a);
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
}
}
This is an old notation known as K & R (Kernighan & Ritchie, after Brian Kernighan and Dennis Ritchie) Notation for declaring the functions. If your compiler supports it, you can use it and it is same as declaring the function with ANSI notation.
As mention by others, this is an early style of function coding.
Following is a pitfall of that style. Be aware there is no type checking on passed parameters. It may explain your run time differences.
Say you declare a function
int foo(a,b,c);
All the compiler sees at that point is a function named "foo" taking 3 arguments and
returning an int. Thus usage checking is limited to that.
Let's assume sizeof(short) < sizeof(int) < sizeof(long) and the function is defined as
int foo(a,b,c)
int a;
long b;
int c;
{ /* code body */ }
Notice the following usage of foo
int d,e,f;
d = foo(1,2L,3);
e = foo((short)1,2L,3);
f = foo(1,2,3);
The first usages works fine, the right size integers are passed to foo.
The 2nd usages also works fine. The first argument is promoted to int size before the call, much like printf("%d", (short)2) promotes (short)2 to int before passing to printf().
The 3rd is a problem as the compiler does not know the second argument needs to be long. Thus the data passed to foo is not passed correctly. --> UB
This is an old C syntax. If your compiler can swallow it then it should work the same as if you have declared the functions the normal, ANSI way.
This is K&R C, i.e, the C language described by the first edition of The C Programming Language by Brian Kernighan and Dennis Ritchie. The second edition has turned to ANSI C(C89).
You shoul always use ANSI C style:
Rationale for International Standard - Programming Languages C 6.11.6 Function declarators
The characterization as obsolescent of the use ofthe “old style” function declarations and
definitions, that is, the traditional style not using prototypes, signals the Committee’s intent that the new prototype style should eventually replace the old style.
The gist of this case is that the new syntax addresses some of the most glaring weaknesses of the language defined in K&R, that the new style is superior to the old style on every count.
It is just a way of declaring types of function parameters:
void func (first_param, second_param)
int first_param;
int second_param;
{
// ...
}
is equal to
void func (int first_param, int second_param)
{
// ...
}
Is it possible to recast the a variable permanently, or have a wrapper function such that the variable would behave like another type?
I would want to achieve something I posted in the other question:
Typecasting variable with another typedef
Update: Added GCC as compiler. May have a extension that would help?
Yes, you can cast a variable from one type to another:
int x = 5;
double y = (double) x; // <== this is what a cast looks like
However, you cannot modify the type of the identifier 'x' in-place, if that is what you are asking. Close to that, though, you can introduce another scope with that identifier redeclared with some new type:
int x = 5;
double y = (double) x;
{
double x = y; // NOTE: this isn't the same as the 'x' identifier above
// ...
}
// NOTE: the symbol 'x' reverts to its previous meaning here.
Another thing you could do, though it is really a horrible, horrible idea is:
int x = 5;
double new_version_of_x = (double) x; // Let's make 'x' mean this
#define x new_version_of_x
// The line above is pure evil, don't actually do it, but yes,
// all lines after this one will think 'x' has type double instead
// of int, because the text 'x' has been rewritten to refer to
// 'new_version_of_x'. This will likely lead to all sorts of havoc
You accomplish that by casting then assigning.
int f(void * p) {
int * i;
i = (int *)p;
//lots of code here with the i pointer, and every line
//really thinks that it is an int pointer and will treat it as such
}
EDIT From the other question you linked:
typedef struct {
unsigned char a;
unsigned char b;
unsigned char c;
} type_a;
typedef struct {
unsigned char e;
unsigned char f[2];
} type_b;
//initialize type a
type_a sample;
sample.a = 1;
sample.b = 2;
sample.c = 3;
Now sample is initialized, but you want to access it differently, you want to pretend that in fact that variable has another type, so you declare a pointer to the type you want to "disguise" sample as:
type_b * not_really_b;
not_really_b = (type_b*)&sample;
See, that is the whole magic.
not_really_b->e is equal 1
not_really_b->f[0] is equal 2
not_really_b->f[1] is equal 3
Does this answer your question?
The other answers are better (declare a variable of the type you want, and do an assignment). If that's not what you're asking for, you could use a macro:
long i;
#define i_as_int ((int)i)
printf( "i = %ld\n", i);
printf( "i = %d\n", i_as_int);
But wouldn't it be clearer to just say (int) i if that's what you mean?
As long as you realize in C pointers are nothing but addresses of memory
locations of certain types, you should have your answer. For example the
following program will print the name of the file
int main(int argc, char *argv[]) {
int *i;
i = (int *) argv[0];
printf("%s\n", argv[0]);
printf("%s\n", ((char *) i));
}