Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiling C structs

Tags:

c

struct

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 the VS developer console, I get this error: error C2440: 'initializing' : cannot convert from 'combination' to 'swag *'. However if I use gcc the console just prints: "GOLD!". Don't understand what's going on here.

like image 838
Anas Ayubi Avatar asked Jan 31 '26 06:01

Anas Ayubi


1 Answers

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

The strict rules of classic C89/90 prohibited the use of non-constant objects in {} initializers. This immediately meant that it was impossible to specify an entire struct object between the {} in the initializer, since that would violate the above requirement. Under that rule you could only use scalar constants between the {}.

However, many C89/90 compilers ignored that standard requirement and allowed users to specify non-constant values when writing {} initializers for local objects. Unfortunately, this immediately created an ambiguity if user specified a complex struct object inside the {} initializer, as in your

safe s = { numbers, "RAMCON" };

The language standard did not allow this, for which reason it was not clear what this numbers initializer should apply to. There are two ways to interpret this:

  1. The existing rules of the language said that the compiler must automatically enter each level of struct nesting and apply sequential initializers from the {} to all sequential scalar fields found in that way (actually, it is a bit more complicated, but that's the general idea).

    This is exactly what your compiler did. It took the first initializer numbers, it found the first scalar field s.numbers.swag and attempted to apply the former to the latter. This expectedly produced the error you observed.

  2. Other compiler took a more elaborate approach to that extension. When the compiler saw that the next initializer from the {} list had the same type as the target field on the left-hand side, it did not "open" the target field and did not enter the next level of nesting, but rather used the whole initializer value to initialize the whole target field.

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

In other words, when you are writing C89/90 code, it is generally OK to use that non-standard extension when you specify non-constant objects in local {} initializers. But it is a good idea to avoid using struct objects in such initializers and stick to scalar initializers only.

like image 195
AnT Avatar answered Feb 02 '26 18:02

AnT



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!