简体   繁体   中英

How to initialize union in struct with C++20 designated initializer

I am trying to initialize struct sigaction (from sigaction.h) using C++20 designated initializers, but there are compiler errors. As this is part of a larger program, I created a short example:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void onSIGINT(int signal, siginfo_t *siginfo, void *context) {
    printf("Caught signal\n");
}

int main(int argc, char** argv) {
    struct sigaction act = {
        .sa_sigaction = onSIGINT,
        .sa_flags = SA_SIGINFO
    };
    if(sigaction(SIGINT, &act, nullptr) != 0) {
        fprintf(stderr, "Failed to listen for SIGINT\n");
        return 1;
    }
    printf("Waiting for signal...\n");
    pause();
    printf("Exit\n");
    return 0;
}

According to https://gcc.gnu.org/projects/cxx-status.html#cxx20 designated initializers are available in gcc8. Running g++ (v8.3.0 on Debian buster) with -std=c++2a gives the following error:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:9: error: expected primary-expression before ‘.’ token
         .sa_sigaction = onSIGINT,
         ^
main.cpp:12:9: error: either all initializer clauses should be designated or none of them should be
         .sa_flags = SA_SIGINFO
         ^

Initializing only sa_flags compiles successfully, initializing only sa_sigaction fails to compile (only first error).

I also tried to initialize __sigaction_handler directly (no using the define to access the union member):

struct sigaction act = {
    .__sigaction_handler = { .sa_sigaction = onSIGINT },
    .sa_flags = SA_SIGINFO
};

That produces a similar error:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:12:34: error: expected primary-expression before ‘.’ token
         .__sigaction_handler = { .sa_sigaction = onSIGINT },
                                  ^

I suppose I am doing something wrong about the union inside the struct, but I can't figure out what.

I am aware that I could achieve roughly the same by zeroing the memory of the struct and then setting callback and flags, but thats not the point.

The problem is that sa_sigaction is a macro , defined to __sigaction_handler.sa_sigaction . This means that your code expands to .__sigaction_handler.sa_sigaction = onSIGINT ; this is valid C, where a named member initializer is allowed to have a complex structure, but it is not valid in C++20.

You can see that by #undef ing it :

#undef sa_sigaction
    .__sigaction_handler = { .sa_sigaction = onSIGINT },

However this is non-portable (undefining a standard library macro, not to mention using a double-underscore prefixed member), so I would recommend against it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM