_Noreturn in a struct in c: error: expected specifier-qualifier-list before '_Noreturn'
_Noreturn in a struct in c: error: expected specifier-qualifier-list before '_Noreturn'
我正在尝试编译一段包含 _Noreturn 的代码:
#ifndef SOMEHEADER_H
#define SOMEHEADER_H
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
extern struct s {
_Noreturn void (*somenoreturnfunc)(bool);
} svar;
#endif
这给了我:
error: expected specifier-qualifier-list before '_Noreturn'
在:
_Noreturn void (*somenoreturnfunc)(bool);
所以我尝试了 的建议:
#ifndef SOMEHEADER_H
#define SOMEHEADER_H
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
#include "noreturn.h"
extern struct s {
noreturn void (*somenoreturnfunc)(bool);
} svar;
#endif
noreturn.h:
#ifndef NO_RETURN_H
#define NO_RETURN_H
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#elif defined(__GNUC__)
#define noreturn __attribute__((noreturn))
#else
#define noreturn
#endif
#endif
但错误仍然存在:
In file included from ../include/someinclude.h:8:0,
from src/main.c:17:
../include/noreturn.h:4:18: error: expected specifier-qualifier-list before '_Noreturn'
#define noreturn _Noreturn
^
../include/someinclude.h:19:5: note: in expansion of macro 'noreturn'
noreturn void (*somenoreturnfunc)(bool);
^
我很困惑,因为它是用 c11 编译的,所以它应该可以工作:
make V=1
cc src/main.c
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -std=c11 -Wall -pedantic -ffreestanding -static -I../libopencm3/include -I../include -DSTM32F1 -g -DDEBUG -DBUILD_STYLE=\"DEBUG\" -O0 -Iinclude -I../librt/include -MMD -MT build/main.o -MF build/main.d -o build/main.o -c src/main.c
In file included...
GCC 版本为 5.4.1:
arm-none-eabi-gcc --version
arm-none-eabi-gcc (15:5.4.1+svn241155-1) 5.4.1 20160919
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
应该支持所有 C11 功能(支持 _Noreturn since 4.7)。
我做错了什么,我该如何解决这个错误?
--
编辑:也许一个独立的示例可以提供帮助:
main.c:
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
struct s {
_Noreturn void (*somenoreturnfunc)(bool);
} svar;
int main()
{
svar.somenoreturnfunc = 0;
return 0;
}
正在编译:
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -std=c11 -Wall -pedantic -ffreestanding -static -DSTM32F1 -g -DDEBUG -DBUILD_STYLE=\"DEBUG\" -O0 -MMD -MT main.o -MF main.d -o main.o -c main.c
main.c:7:5: error: expected specifier-qualifier-list before '_Noreturn'
_Noreturn void (*somenoreturnfunc)(bool);
^
main.c:5:8: warning: struct has no members [-Wpedantic]
struct s {
^
main.c: In function 'main':
main.c:12:6: error: 'struct s' has no member named 'somenoreturnfunc'
svar.somenoreturnfunc = 0;
^
然而,当使用相同的命令行编译并删除 _Noreturn
时,编译成功。
编译时也会发生这种情况
gcc -std=c11 -o main main.c
:
$ gcc -std=c11 -o main main.c
main.c:7:5: error: expected specifier-qualifier-list before ‘_Noreturn’
_Noreturn void (*somenoreturnfunc)(bool);
^~~~~~~~~
main.c: In function ‘main’:
main.c:12:6: error: ‘struct s’ has no member named ‘somenoreturnfunc’
svar.somenoreturnfunc = 0;
^
$ gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
在 ISO C 中,_Noreturn
不能用于函数指针的声明。它只能用于函数的声明。 (参考:C11 6.7.4/2)。
你将不得不放弃这个想法。函数说明符(inline
和 _Noreturn
)不是函数类型的一部分。
您的代码中还有另一个问题:您在 header 中定义 svar
,如果 header 包含在两个或多个翻译单元中,这将导致 ODR 违规。它应该只在header中有一个声明,在一个单元中有一个定义。
通过函数指针调用并保留_Noreturn
语义,也许你可以做一个垫片,例如:
inline _Noreturn void call_somefunc( struct s *ps, bool b )
{
ps->somenoreturnfunc(b);
}
但是没有办法让编译器强制执行,当你分配给函数指针时,它实际上是一个 _Noreturn
函数。
函数说明符 _Noreturn
和 inline
不是函数类型的一部分,它们是声明的一部分。 C17 标准在 6.7.4 中声明函数说明符 "shall be used only in the declaration of an identifier for a function." 这意味着它们不能用于函数的 指针 的声明中。
很遗憾,这是不可能的; typedef 也无济于事。
已经有很多好的答案,但为了清楚起见,我想补充以下内容:
来自 C11,6.7.4.9:
The implementation should produce a diagnostic message for a function declared with a _Noreturn function specifier that appears to be capable of returning to its caller.
所以 _Noreturn 的目的是通知编译器检查声明为 _Noreturn 的函数中没有控制路径,实际上它 returns.
知道了这一点,现在就清楚了为什么不能将函数指针声明为 _Noreturn,因为编译器无法检查所分配函数的 return 语义。
(当然,编译器可以将 _Noreturn 视为类型的一部分,然后检查是否只有 _Noreturn 函数分配给函数指针。标准中的当前定义似乎对我来说有点没用。)
我正在尝试编译一段包含 _Noreturn 的代码:
#ifndef SOMEHEADER_H
#define SOMEHEADER_H
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
extern struct s {
_Noreturn void (*somenoreturnfunc)(bool);
} svar;
#endif
这给了我:
error: expected specifier-qualifier-list before '_Noreturn'
在:
_Noreturn void (*somenoreturnfunc)(bool);
所以我尝试了
#ifndef SOMEHEADER_H
#define SOMEHEADER_H
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
#include "noreturn.h"
extern struct s {
noreturn void (*somenoreturnfunc)(bool);
} svar;
#endif
noreturn.h:
#ifndef NO_RETURN_H
#define NO_RETURN_H
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#elif defined(__GNUC__)
#define noreturn __attribute__((noreturn))
#else
#define noreturn
#endif
#endif
但错误仍然存在:
In file included from ../include/someinclude.h:8:0,
from src/main.c:17:
../include/noreturn.h:4:18: error: expected specifier-qualifier-list before '_Noreturn'
#define noreturn _Noreturn
^
../include/someinclude.h:19:5: note: in expansion of macro 'noreturn'
noreturn void (*somenoreturnfunc)(bool);
^
我很困惑,因为它是用 c11 编译的,所以它应该可以工作:
make V=1
cc src/main.c
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -std=c11 -Wall -pedantic -ffreestanding -static -I../libopencm3/include -I../include -DSTM32F1 -g -DDEBUG -DBUILD_STYLE=\"DEBUG\" -O0 -Iinclude -I../librt/include -MMD -MT build/main.o -MF build/main.d -o build/main.o -c src/main.c
In file included...
GCC 版本为 5.4.1:
arm-none-eabi-gcc --version
arm-none-eabi-gcc (15:5.4.1+svn241155-1) 5.4.1 20160919
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
应该支持所有 C11 功能(支持 _Noreturn since 4.7)。
我做错了什么,我该如何解决这个错误?
--
编辑:也许一个独立的示例可以提供帮助:
main.c:
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
struct s {
_Noreturn void (*somenoreturnfunc)(bool);
} svar;
int main()
{
svar.somenoreturnfunc = 0;
return 0;
}
正在编译:
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -std=c11 -Wall -pedantic -ffreestanding -static -DSTM32F1 -g -DDEBUG -DBUILD_STYLE=\"DEBUG\" -O0 -MMD -MT main.o -MF main.d -o main.o -c main.c
main.c:7:5: error: expected specifier-qualifier-list before '_Noreturn'
_Noreturn void (*somenoreturnfunc)(bool);
^
main.c:5:8: warning: struct has no members [-Wpedantic]
struct s {
^
main.c: In function 'main':
main.c:12:6: error: 'struct s' has no member named 'somenoreturnfunc'
svar.somenoreturnfunc = 0;
^
然而,当使用相同的命令行编译并删除 _Noreturn
时,编译成功。
编译时也会发生这种情况
gcc -std=c11 -o main main.c
:
$ gcc -std=c11 -o main main.c
main.c:7:5: error: expected specifier-qualifier-list before ‘_Noreturn’
_Noreturn void (*somenoreturnfunc)(bool);
^~~~~~~~~
main.c: In function ‘main’:
main.c:12:6: error: ‘struct s’ has no member named ‘somenoreturnfunc’
svar.somenoreturnfunc = 0;
^
$ gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
在 ISO C 中,_Noreturn
不能用于函数指针的声明。它只能用于函数的声明。 (参考:C11 6.7.4/2)。
你将不得不放弃这个想法。函数说明符(inline
和 _Noreturn
)不是函数类型的一部分。
您的代码中还有另一个问题:您在 header 中定义 svar
,如果 header 包含在两个或多个翻译单元中,这将导致 ODR 违规。它应该只在header中有一个声明,在一个单元中有一个定义。
通过函数指针调用并保留_Noreturn
语义,也许你可以做一个垫片,例如:
inline _Noreturn void call_somefunc( struct s *ps, bool b )
{
ps->somenoreturnfunc(b);
}
但是没有办法让编译器强制执行,当你分配给函数指针时,它实际上是一个 _Noreturn
函数。
函数说明符 _Noreturn
和 inline
不是函数类型的一部分,它们是声明的一部分。 C17 标准在 6.7.4 中声明函数说明符 "shall be used only in the declaration of an identifier for a function." 这意味着它们不能用于函数的 指针 的声明中。
很遗憾,这是不可能的; typedef 也无济于事。
已经有很多好的答案,但为了清楚起见,我想补充以下内容:
来自 C11,6.7.4.9:
The implementation should produce a diagnostic message for a function declared with a _Noreturn function specifier that appears to be capable of returning to its caller.
所以 _Noreturn 的目的是通知编译器检查声明为 _Noreturn 的函数中没有控制路径,实际上它 returns.
知道了这一点,现在就清楚了为什么不能将函数指针声明为 _Noreturn,因为编译器无法检查所分配函数的 return 语义。
(当然,编译器可以将 _Noreturn 视为类型的一部分,然后检查是否只有 _Noreturn 函数分配给函数指针。标准中的当前定义似乎对我来说有点没用。)