compilation error in c struct variable assignment - c

Got a doubt in struct variable assignment.
struct udata
{
char name[50];
int num;
char ch;
};
void main()
{
struct udata a = {"ram", 20, 'a'};
struct udata b;
//b = {"ashok", 10, 'c'}; - illegal
b = a;
}
In above code b = {"ashok", 10, 'c'}; is giving compilation error but its accepting b = a;. I hope both are similar kind of assignment, but I dont know why its not accepting first one. Can someone explain me why it is so ?
Note : I am compiling in a fedora gcc compiler.

Initializers can only be used at declaration time. If you want to initialize b after declaration, then you can do it by using a compound literal-- a C99 feature:
b = (struct udata){"ashok", 10, 'c'};
GCC also support copound literals as an extension.

What you're trying to do cannot be done directly in standard C. The best standard and portable solution is to use a temporary:
const struct udata tmp = {"ashok", 10, 'c'};
b = tmp;
However, in practice, the following is often (but not always!) allowed by compilers (*note below):
b = (struct udata){...};
(* note: I believe at least MSVC does not support this syntax, and probably many others; but just throwing it out there. GCC, however, does support it)

That's how C is designed and specified to work. There's nothing you can do. If you have a structure variable, you can only initialize it by an initializer in the declaration or by later initializing the individual members.
In the future, when posting a question regarding compiler errors, please include the complete and unedited error log in the question.

Related

why compiler restricts global variable always to be initialized by constant value? [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 9 years ago.
Let me exemplify this,
int a = 100;
int b = a;
int main(int argc, char **argv, char ** env)
{
printf("The value of b=%d\r\n",b);
return 0;
}
Now, I get the compilation error as expected.
[joshis1#localhost global_var]$ gcc global_var.c -o global_var.out
global_var.c:4:1: error: initializer element is not constant
int b = a;
^
What I want to learn here is why do I get the error? why compiler restricts this operation.
I understand that initialized global variables are stored in Data segments. The compiler could have first resolved the value of a,and then could have assigned the same value to b. Why it lacks this feature? Is it complex for compiler to do? Is there any rationale behind this functionality or just a pitfall of C?
The official documentation, taken from line 1644, 6.7.8 Initialization, says:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
Why the rule exists is a more difficult question - perhaps as you suggest it is difficult for the compiler to do. In C++ such an expression is valid, but global initialiser may invoke constructors, etc, whereas for C, to keep things compact, globals are evaluated at the compile phase. int b = a; is evaluable at compile time, but what about int b = a + c;? int b = pow(a, 2);? Where would you stop? C decides that not allowing you to start is the best solution.
From your comment:
...how can I force compiler to make this work?
Well you can't make the compiler accept what you have but you can accomplish your goal by defining the value you want to assign to both variables.
#define INITIAL_VALUE_FOR_A 100
int a = INITIAL_VALUE_FOR_A;
int b = INITIAL_VALUE_FOR_A;
Now if you need to change the initial value, you only need to change it in one place;
C is portable to very simple, small machines. Evaluating expressions that aren't constant requires runtime code, in a function. In embedded programming you might not want any functions (or code) that you did not explicitly program.
Your compiler probably will evaluate the initializer as a language extension, if configured with different options. If that fails, you could try C++ (even just the C-like subset) or another language that does more things you like :v) .
Others have stated why initializers in general can't be allowed to be arbitrary expressions.
The way to "force the compiler to accept the code" is to change the code. The canonical way to perform arbitrary initialization of file scope, external linkage (vulgo: "global") variables is to call an initialization function at the start of main() that does all the initialization in the sequence you need:
#include <stdio.h>
int a;
int b;
void init(void)
{
a = 100;
b = a;
}
int main(int argc, char **argv)
{
init();
printf("The value of b=%d\n", b);
return 0;
}

unusual struct definition in C [duplicate]

This question already has answers here:
What does a dot before the variable name in struct mean?
(2 answers)
Closed 9 years ago.
I am looking at some code that has this kind of struct definition in it. At first, I thought it was a special way of defining a struct that defined it and instantiated one at the same time. However, my predictions about how this type of code behaves were wrong after I tested some similar code myself. Can someone tell me what this code does/where I could look online to see a description of this kind of code?
struct Error e = { .code = 22,
.msg = 22100 };
That's not a struct definition, it's a designated initializer. It's setting the code field to 22 and the msg field to 22100. Logically, you could rewrite it something like:
struct Error e = {0};
e.code = 22;
e.msg = 22100;
You can do something similar with arrays:
int a[5] = {
[3] = 12,
[4] = 17
};
It's a C99 designation initializer.
Designation initializers allow you to initialize aggregate members in any order and they also allow you to omit members. Members that are not designated explicitly are initialized to 0.
For example, a initialization here:
struct bla {int x; int y; int z;};
struct bla a = {.x =1, .z = 1};
is equivalent to C89 initialization below:
struct bla a = {1, 0, 1};
A note on terminology, it's a designation initializer and not a designated initializer. See defect report DR#253:
"The tem "designated initializer" is never mentioned in the Standard though it appears in the index and new features section (the Standard uses the term "designation initializer" in the text).
This is called a designated initializer, it's initializing an instance of the struct.
Here’s GCC’s manual page about how to use them.

void* type cast breaks strict -aliasing?

I wrote a dynamic array like this:
#include <stdlib.h>
typedef struct {
size_t capacity;
size_t len;
} __dynarray_header;
void* dynarray_new() {
__dynarray_header* header = malloc(sizeof(__dynarray_header));
header->capacity = 0;
header->len = 0;
return header + 1;
}
The dynamic array can be accessed with a [] operation. When resizing, I can use __dynarray_header*)array - 1 to retrieve capacity and length information.
The idea works in small tests. However, GCC warns about breaking strict-aliasing.
I've also found some larger projects segfault without the -fno-strict-aliasing compiler option (with -O3 optimization).
I know what strict-aliasing is, and why my code breaks strict-aliasing.
My question is: Is there a better way to implement a dynamic array supporting both the [] operation and dynamic resizing than the one I showed above?
Extra:
A demo program using this dynamic array:
int* arr = dynarray_new();
arr = dynarray_resize(sizeof(int) * 2);
arr[0] = 1;
arr[1] = 2;
arr = dynarray_resize(sizeof(int) * 4);
arr[2] = 3;
arr[3] = 4;
dynarray_free(arr);
The technique that the C standard foresees for such a thing are flexible arrays, as was already mentionned:
typedef struct {
size_t capacity;
size_t len;
unsigned char data[];
} dynarray_header;
If you allocate (or re-allocate) such a struct with enough space you may access the data element like any unsigned char array. char types may alias any other data type, so you wouldn't have problems with that.
If your compiler doesn't support flexible arrays, just put a [1] in there for data.
BTW, names starting with underscores are reserved in file scope, you are not supposed to use these.
The main optimization afforded by -fstrict-aliasing is that references to foo * can be arbitrarily moved past references to bar * in most circumstances. The segfaults you see are likely due to a reference getting moved past a free type operation somewhere.
While this feels a little dirty, you may be able to make it work under C89 by adding a union of prospective array element types into your structure, such as:
typedef struct {
size_t capacity;
size_t len;
union {
int i;
double d;
my_type mt;
etc e;
/* add additional types here. */
} array_head;
} __dynarray_header;
Then, instead of returning header + 1, return (void *)&(header->array_head).
Now, even with strict aliasing, the compiler is more likely to consider a pointer to __dynarray_header to possibly alias a pointer to anything in that union, unless the pointers are also restrict-qualified. (I'm assuming for your use case, they are not, at least in the contexts that trigger seg-faults.)
Still... as Dennis Ritchie said, it seems like "unwarranted chumminess with the implementation." Or, in other words, a hack. Good luck!
(Edit: As Carl above reminded me, in C99 you can use flexible array members. I haven't used them, simply because C99 support doesn't seem to be the default in the C compilers I use. Here's IBM's reference: http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzarg%2Fflexible.htm )

Why GCC compiles this erroneous code?

I tried to compile something like:
struct A
{ int a;
struct B
{ int c;
};
};
Now when I compile this code the compiler gives me a warning message that:
declaration does not declare anything [enabled by default]
I know that I have not defined any instance of struct B. That will mean that I shall not be able to access variable c. Still compiler compiles this code with a warning. What's the whole point ? Why does not the compiler give a compilation error instead ?
ADDED Info:
The size of the struct A is equal to the size of int on my machine!!
Because you can do this:
struct A
{ int a;
struct B
{ int c;
};
};
int main()
{
struct A a = {1};
struct B b = {2};
return a.a + b.c;
}
Note:
you need a semicolon after declaring B, which your code is missing
this isn't particularly useful, but I suppose it might serve some documentary purpose (ie,to suggest a relationship or grouping between types)
in C++, the second variable would have type A::B, but C doesn't have the same scoping rules (all structs just belong to the global struct namespace, in effect)
As to the motivation for allowing it ...
struct Outer {
struct {
int b;
} anon;
/* this ^ anonymous struct can only be declared inside Outer,
because there's no type name to declare anon with */
struct Inner {
int c;
} named;
/* this ^ struct could be declared outside, but why force it to be
different than the anonymous one? */
struct Related {
double d;
};
/* oh no we have no member declared immediately ... should we force this
declaration to be outside Outer now? */
struct Inner * (*function_pointer)(struct Related *);
/* no member but we are using it, now can it come back inside? */
struct Related excuse;
/* how about now? */
};
Once you've allowed nested type declarations like this, I doubt there's any particular motivation to require there be a member of that type right away.
It's legal (but extremely bad style) to do:
struct A {
int a;
struct B {
int c;
};
};
struct B B_instance;
struct A A_instance;
And the compiler doesn't know about the later variables that use the struct types, so it really should not error out.
Generally, a warning means the code likely does not do what you intended but is legal in the language. The compiler is saying, “This is likely not what you really wanted to do, but I must allow you to do it because the language says it is allowed.” The compiler cannot give you an error for this code because the C standard permits it, so it must be allowed (unless you specifically ask for errors for such things, as by using GCC’s -Werror option to turn warnings into errors).
The C standard does not attempt to define everything that makes sense in a program. For example, these things are legal in C:
3;
if (x) then foo(); else foo();
x = 4*0;
The first statement has no side effects, and its return value is not used. But it is legal in C, since a statement may be just an expression. The second statement just calls foo(), so the if is pointless. In the third statement, multiplying by four is pointless.
It would be extremely difficult to write a C standard that prohibited all things that did not make sense. And it is certainly not worth the effort. So this is part of your answer: When the committee writing the C standard builds the language, do they want to spend a lot of time rewriting the technical specification to exclude things that do not make sense? Sometimes yes, if it seems valuable to avoid something that could cause serious bugs. But much of the time, it is just not worth their time and would complicate the specification unnecessarily.
However, compilers can recognize some of these things and warn you. This helps catch many typographical errors or other mistakes.
On the other hand, sometimes these constructions arise from unusual circumstances. For example, a program may have preprocessor statements that define struct A in different ways when building for different targets or different features. In some of those targets, it may be that the struct B member is not needed in struct A, so it is not declared, but the declaration of struct B (the type, not the object) remains present just because it was easier to write the preprocessor statements that way.
So the compiler needs to permit these things, to avoid interfering with programmers writing a wide variety of programs.
You are, in fact, declaring struct B here, but you are not declaring a variable of that type.
This is a warning, but one you should fix. Perhaps you meant:
struct A
{ int a;
struct B
{
int c;
} c;
};

Is it possible to cast pointers from a structure type to another structure type extending the first in C?

If I have structure definitions, for example, like these:
struct Base {
int foo;
};
struct Derived {
int foo; // int foo is common for both definitions
char *bar;
};
Can I do something like this?
void foobar(void *ptr) {
((struct Base *)ptr)->foo = 1;
}
struct Derived s;
foobar(&s);
In other words, can I cast the void pointer to Base * to access its foo member when its type is actually Derived *?
You should do
struct Base {
int foo;
};
struct Derived {
struct Base base;
char *bar;
};
to avoid breaking strict aliasing; it is a common misconception that C allows arbitrary casts of pointer types: although it will work as expected in most implementations, it's non-standard.
This also avoids any alignment incompatibilities due to usage of pragma directives.
Many real-world C programs assume the construct you show is safe, and there is an interpretation of the C standard (specifically, of the "common initial sequence" rule, C99 §6.5.2.3 p5) under which it is conforming. Unfortunately, in the five years since I originally answered this question, all the compilers I can easily get at (viz. GCC and Clang) have converged on a different, narrower interpretation of the common initial sequence rule, under which the construct you show provokes undefined behavior. Concretely, experiment with this program:
#include <stdio.h>
#include <string.h>
typedef struct A { int x; int y; } A;
typedef struct B { int x; int y; float z; } B;
typedef struct C { A a; float z; } C;
int testAB(A *a, B *b)
{
b->x = 1;
a->x = 2;
return b->x;
}
int testAC(A *a, C *c)
{
c->a.x = 1;
a->x = 2;
return c->a.x;
}
int main(void)
{
B bee;
C cee;
int r;
memset(&bee, 0, sizeof bee);
memset(&cee, 0, sizeof cee);
r = testAB((A *)&bee, &bee);
printf("testAB: r=%d bee.x=%d\n", r, bee.x);
r = testAC(&cee.a, &cee);
printf("testAC: r=%d cee.x=%d\n", r, cee.a.x);
return 0;
}
When compiling with optimization enabled (and without -fno-strict-aliasing), both GCC and Clang will assume that the two pointer arguments to testAB cannot point to the same object, so I get output like
testAB: r=1 bee.x=2
testAC: r=2 cee.x=2
They do not make that assumption for testAC, but — having previously been under the impression that testAB was required to be compiled as if its two arguments could point to the same object — I am no longer confident enough in my own understanding of the standard to say whether or not that is guaranteed to keep working.
That will work in this particular case. The foo field in the first member of both structures and hit has the same type. However this is not true in the general case of fields within a struct (that are not the first member). Items like alignment and packing can make this break in subtle ways.
As you seem to be aiming at Object Oriented Programming in C I can suggest you to have a look at the following link:
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf
It goes into detail about ways of handling oop principles in ANSI C.
In particular cases this could work, but in general - no, because of the structure alignment.
You could use different #pragmas to make (actually, attempt to) the alignment identical - and then, yes, that would work.
If you're using microsoft visual studio, you might find this article useful.
There is another little thing that might be helpful or related to what you are doing ..
#define SHARED_DATA int id;
typedef union base_t {
SHARED_DATA;
window_t win;
list_t list;
button_t button;
}
typedef struct window_t {
SHARED_DATA;
int something;
void* blah;
}
typedef struct window_t {
SHARED_DATA;
int size;
}
typedef struct button_t {
SHARED_DATA;
int clicked;
}
Now you can put the shared properties into SHARED_DATA and handle the different types via the "superclass" packed into the union.. You could use SHARED_DATA to store just a 'class identifier' or store a pointer.. Either way it turned out handy for generic handling of event types for me at some point. Hope i'm not going too much off-topic with this
I know this is an old question, but in my view there is more that can be said and some of the other answers are incorrect.
Firstly, this cast:
(struct Base *)ptr
... is allowed, but only if the alignment requirements are met. On many compilers your two structures will have the same alignment requirements, and it's easy to verify in any case. If you get past this hurdle, the next is that the result of the cast is mostly unspecified - that is, there's no requirement in the C standard that the pointer once cast still refers to the same object (only after casting it back to the original type will it necessarily do so).
However, in practice, compilers for common systems usually make the result of a pointer cast refer to the same object.
(Pointer casts are covered in section 6.3.2.3 of both the C99 standard and the more recent C11 standard. The rules are essentially the same in both, I believe).
Finally, you've got the so called "strict aliasing" rules to contend with (C99/C11 6.5 paragraph 7); basically, you are not allowed to access an object of one type via a pointer of another type (with certain exceptions, which don't apply in your example). See "What is the strict-aliasing rule?", or for a very in-depth discussion, read my blog post on the subject.
In conclusion, what you attempt in your code is not guaranteed to work. It might be guaranteed to always work with certain compilers (and with certain compiler options), and it might work by chance with many compilers, but it certainly invokes undefined behavior according to the C language standard.
What you could do instead is this:
*((int *)ptr) = 1;
... I.e. since you know that the first member of the structure is an int, you just cast directly to int, which bypasses the aliasing problem since both types of struct do in fact contain an int at this address. You are relying on knowing the struct layout that the compiler will use and you are still relying on the non-standard semantics of pointer casting, but in practice this is significantly less likely you give you problems.
The great/bad thing about C is that you can cast just about anything -- the problem is, it might not work. :) However, in your case, it will*, since you have two structs whose first members are both of the same type; see this program for an example. Now, if struct derived had a different type as its first element -- for example, char *bar -- then no, you'd get weird behavior.
* I should qualitfy that with "almost always", I suppose; there're a lot of different C compilers out there, so some may have different behavior. However, I know it'll work in GCC.

Resources