【问题标题】:How to initialize union in struct with C++20 designated initializer如何使用 C++20 指定初始化程序初始化结构中的联合
【发布时间】:2021-03-25 01:39:50
【问题描述】:

我正在尝试使用 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 },
                                  ^

我想我对结构内的联合做错了什么,但我不知道是什么。

我知道我可以通过将结构的内存归零然后设置回调和标志来实现大致相同的效果,但这不是重点。

【问题讨论】:

  • 你的编译器版本是多少?运行gcc --version

标签: c++ gcc c++20


【解决方案1】:

问题在于sa_sigaction is a macro,定义为__sigaction_handler.sa_sigaction。这意味着您的代码扩展为.__sigaction_handler.sa_sigaction = onSIGINT;这是有效的 C,其中允许命名成员初始化程序具有复杂结构,但在 C++20 中无效。

你可以通过#undefing it看到:

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

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

【讨论】:

  • 感谢您的解释,取消定义宏实际上使其编译。我明白你的观点,这最终很丑陋。所以整个问题源于sa_sigaction同时是一个宏和一个成员名称,而编译器在给定.__sigaction_handler = { .sa_sigaction = onSIGINT }时更喜欢宏?
  • 是的,但是宏是在定义成员名称之后定义的,因此从那时起,具体输出成员名称的唯一方法是取消定义宏。
猜你喜欢
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 2020-03-11
相关资源
最近更新 更多