Compiling C Structures

This is my code:

#include <stdio.h>
typedef struct {
    const char *description;
    float value;
    int age;
} swag;

typedef struct {
    swag *swag;
    const char *sequence;
} combination;

typedef struct {
    combination numbers;
    const char *make;
} safe;

int main(void)
{
    swag gold = { "GOLD!", 100000.0 };
    combination numbers = { &gold, "6503" };
    safe s = { numbers, "RAMCON" };

    printf("Contents = %s\n", s.numbers.swag->description);

    getchar();

    return 0;
}

      

Whenever I compile it with VS dev console I get this error: error C2440: "initializing": cannot convert from "combination" to "swag *". However, if I use gcc, the console just prints "GOLD!" I don't understand what's going on here.

+3


source to share


2 answers


What you stumble upon is an implementation variant of a popular non-standard compiler extension used in various C89 / 90 compilers.

The strict rules of the classic C89 / 90 prohibit the use of non-persistent objects in initializers {}

. This immediately meant that it was not possible to specify a whole object in struct

between {}

in the initializer as it would violate the above requirement. Under this rule, you can only use scalar constants between {}

.

However, many C89 / 90 compilers ignored this standard requirement and allowed users to specify non-constant values ​​when writing initializers {}

for local objects. Unfortunately this immediately created an ambiguity if the user specified a complex object struct

inside an initializer {}

like in your

safe s = { numbers, "RAMCON" };

      



The locale did not allow this, for this reason it was not clear what this initializer should be applied to numbers

. There are two ways to interpret this:

  • Existing language rules say that the compiler should automatically inject each struct

    nesting level and apply sequential initializers from {}

    to all sequential scalar fields found in this way (actually it's a bit more complicated, but that's the general idea).

    This is exactly what your compiler did. He took the first initializer numbers

    , he found the first scalar field, s.numbers.swag

    and tried to apply the first to the last. This, as expected, caused the error you observed.

  • Another compiler took a more verbose approach to this extension. When the compiler saw that the next initializer from the list {}

    was of the same type as the target field on the left side, it did not "open" the target field and enter the next nesting level, but rather used the entire initializer value to initialize the entire target field.

This latter behavior is what you expected in your example (and if I'm not mistaken, this is the behavior required by C99), but your C89 / 90 compiler behaved according to the first approach.

In other words, when you write C89 / 90 code, it is generally recommended that you use this non-standard extension when you specify non-persistent objects in local initializers {}

. But it is recommended to avoid using objects struct

in such initializers and stick to only scalar initializers.

+4


source


Looks like a problem with initializers. If you are using the correct options with gcc, it will tell you this:

$ gcc -Wall -ansi -pedantic x.c
x.c: In function β€˜main’:
x.c:21: warning: initializer element is not computable at load time
x.c:22: warning: initializer element is not computable at load time

      



which probably refers to the same problem that VS is trying to tell you. You can do this by declaring statics gold

and numbers

.

0


source







All Articles