1

I'm compiling my program using these gcc flags: -std=c11 -Wall -Wextra -pedantic.

I'm trying to initialize a struct using an initializer with the field labels, instead to remember the correct order of each field. However I'm getting some warnings that I do not understand. In another question someone claims that it's a gcc bug possibly... I don't know about that.

Here is my code. I tried to use the colon : notation but I was getting an obsolete initializer warning so I switched to dot . notation.

Is it really just a bug, or I'm doing something wrong here? I could just suppress that warning, but I was thinking that it shouldn't be there in the first place. I double-checked my code, and it should be correct, right? The compiler should be happy and not make that warning.

Let me know if I'm mistaken, or if I forgot something

EDIT: Is the "thing" I'm trying to do really C11 standard or not? Can I 'extend' a struct in C?

EDIT 2: Solved. See my answer below

student/student.h:

#ifndef STUDENT_H
#define STUDENT_H

#define IDSIZE 7 + 1 // 7x char + '\0' terminator

typedef enum gender {
    MALE = 'M',
    FEMALE = 'F',
    OTHER = 'O'
} gender_t;

typedef struct date {
    short day;
    short month;
    int year;
} date_t;

typedef struct person {
    char *firstname;
    char *lastname;
    date_t birthdate;
    gender_t gender;
} person_t;

typedef struct student {
    char id[IDSIZE];

    struct person; // "extends" from struct person
} student_t;

#endif

es3.c:

/**
 * Trying to refactor the student crazy shit stuff of a previous exercise.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "student/student.h"

void die(const char * format, ...);

int main(int argc, char **argv) {
    if (argc < 2)
        die("Usage: %s inputfile.txt\n", argv[0]);

    puts("Ok");

    student_t student = {
        .id = "s184728",
        .firstname = "Tommaso",
        .lastname = "Ricci",
        .birthdate = {
            .day = 10,
            .month = 7,
            .year = 1992
        },
        .gender = MALE
    };

    return EXIT_SUCCESS;
}

void die(const char *format, ...) {
    va_list args;
    va_start (args, format);

    vfprintf(stderr, format, args);

    va_end (args);
    exit(EXIT_FAILURE);
}

Makefile:

NAME= es3
BIN= bin
SRC= src
EXE:= $(BIN)/$(NAME)
INPUT= input.txt

#RM=rm -rf
#CC=gcc

OBJS:= $(BIN)/$(NAME).o
FLAGS= -std=c11 -Wall -Wextra -pedantic

all: $(EXE)
$(EXE): $(OBJS)
    $(CC) $(FLAGS) $(OBJS) -o $(EXE)

$(BIN)/$(NAME).o: $(SRC)/$(NAME).c
    $(CC) $(FLAGS) -c $(SRC)/$(NAME).c -o $(BIN)/$(NAME).o

.PHONY: clean
clean:
    $(RM) $(EXE) $(OBJS)

.PHONY: run
run: $(EXE)
    @$(EXE) $(INPUT)

The initializer of every variable is present, but it still says missing initializer

gcc output:

$ make
cc -std=c11 -Wall -Wextra -pedantic -c src/es3.c -o bin/es3.o
src/es3.c: In function ‘main’:
src/es3.c:22:9: warning: missing initializer for field ‘lastname’ of ‘struct person’ [-Wmissing-field-initializers]
         .lastname = "Ricci",
         ^
In file included from src/es3.c:9:0:
src/student/student.h:20:8: note: ‘lastname’ declared here
  char *lastname;
        ^
src/es3.c:23:9: warning: missing initializer for field ‘birthdate’ of ‘struct person’ [-Wmissing-field-initializers]
         .birthdate = {
         ^
In file included from src/es3.c:9:0:
src/student/student.h:21:9: note: ‘birthdate’ declared here
  date_t birthdate;
         ^
src/es3.c:28:9: warning: missing initializer for field ‘gender’ of ‘struct person’ [-Wmissing-field-initializers]
         .gender = MALE
         ^
In file included from src/es3.c:9:0:
src/student/student.h:22:11: note: ‘gender’ declared here
  gender_t gender;
           ^
src/es3.c:19:15: warning: unused variable ‘student’ [-Wunused-variable]
     student_t student = {
               ^
cc -std=c11 -Wall -Wextra -pedantic bin/es3.o -o bin/es3

If I understand correctly the : notation is obsolete

I'm using gcc version 4.9.3 (GCC) on Cygwin64.

Possible related questions I found, but didn't solve my issue:

Community
  • 1
  • 1
Zorgatone
  • 4,176
  • 4
  • 30
  • 47

2 Answers2

3

C11 section 6.7.2.1p13 states:

An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

It seems we've both misread this (thanks, Dror K, for pointing that out). A tagless version of your code should look like this:

typedef struct student {
    char id[IDSIZE];

    struct { // <--- note the lack of tag here <---
        char *firstname;
        char *lastname;
        date_t birthdate;
        gender_t gender;
    };
} student_t;

Nonetheless, we can only conclude that your compiler supports C11 if we can find documentation to suggest that your compiler supports C11. Alas, I tried to find such documentation earlier when I ran into another C11-related problem, and it doesn't seem like Cygwin documents any C11 support. If you require C11 support, you might want to consider using llvm/clang on Windows, instead.

autistic
  • 1
  • 3
  • 35
  • 80
0

Solved changing my header code.

What I was trying to do wasn't standard, but implementation-specific to gcc (I think).

This code is working now, and it isn't giving initializer errors anymore:

#ifndef STUDENT_H
#define STUDENT_H

#define IDSIZE 7 + 1 // 7x char + '\0' terminator

typedef enum gender {
    MALE = 'M',
    FEMALE = 'F',
    OTHER = 'O'
} gender_t;

typedef struct date {
    short day;
    short month;
    int year;
} date_t;

typedef struct student {
    char id[IDSIZE];
    char *firstname;
    char *lastname;
    date_t birthdate;
    gender_t gender;
} student_t;

#endif

See also here for GCC reference: https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html

Zorgatone
  • 4,176
  • 4
  • 30
  • 47
  • There was nothing wrong with your original code. Compiles just fine with `gcc -std=c11 -pedantic-errors -Wall -Wextra`. Please note that [-Wextra is a bit stupid](http://stackoverflow.com/questions/22194935/wmissing-field-initializer-when-using-designated-initializers) when it comes to designated initializers, it is a flaw/bug in gcc. – Lundin Dec 08 '15 at 08:41
  • What I wrote before was just a GCC extension, then if it's not portable I don't want to use it. But I agree that if GCC supported that, it shouldn't give that warning – Zorgatone Dec 08 '15 at 09:23
  • When you say -std=c11 -pedantic, you're requesting it not support non-standard extensions. You can't really have it both ways. – Randy Howard Jan 15 '16 at 23:39