gcc 如何用C++20指定的初始化器初始化结构体中的联合

lsmd5eda  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(155)

我尝试使用C++20指定的初始化器初始化struct sigaction(来自sigaction.h),但出现编译器错误。由于这是一个更大的程序的一部分,我创建了一个简短的示例:

#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;
}

根据https://gcc.gnu.org/projects/cxx-status.html#cxx20,指定的初始化器在gcc8中可用。使用-std=c++2a运行g++(Debian buster上的v8.3.0)会出现以下错误:

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
         ^

仅初始化sa_flags编译成功,仅初始化sa_sigaction编译失败(只有第一个错误)。
我还尝试直接初始化__sigaction_handler(不使用define来访问联合成员):

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

这会产生类似的错误:

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

我想我在结构体内部的联合上做错了什么,但我不知道是什么。
我知道,我可以通过将结构体的内存归零,然后设置回调和标志来实现大致相同的效果,但这不是重点。

kjthegm6

kjthegm61#

问题是sa_sigaction是一个宏,定义为__sigaction_handler.sa_sigaction。这意味着代码扩展到.__sigaction_handler.sa_sigaction = onSIGINT;这是有效的C,其中允许命名成员初始化器具有复杂的结构,但在C++20中它无效。
你可以看到#undef ing it

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

然而,这是不可移植的(取消定义标准库宏,更不用说使用双下划线前缀成员),所以我建议不要这样做。

rjjhvcjd

rjjhvcjd2#

虽然ecatmur在诊断这个问题上是正确的(sa_sigaction是一个宏,它转换为嵌套的指定初始化器,这是一个C99功能,尚未添加到C++,截至C++23),解决这个问题的最可行的方法确实是通过将结构体的内存归零,然后设置回调和标志,正如问题所提出的那样。

struct sigaction sa {};
    sa.sa_sigaction = onSIGINT;
    sa.sa_flags     = static_cast<int>(SA_SIGINFO | SA_RESETHAND),

相关问题