C 预处理无法在 #error 后立即停止

C preprocessing fails to stop immediately after an #error

我今天的问题应该不是很复杂,但是我就是找不到reason/solution。作为一个可重现的小例子,请考虑以下玩具 C 代码

#define _state_ 0

#if _state_ == 1
int foo(void) {return 1;}
#else

/* check GCC flags first
   note that -mfma will automatically turn on -mavx, as shown by [gcc -mfma -dM -E - < /dev/null | egrep "SSE|AVX|FMA"]
   so it is sufficient to check for -mfma only */

#ifndef __FMA__
#error "Please turn on GCC flag: -mfma"
#endif

#include <immintrin.h>  /* All OK, compile C code */
void foo (double *A, double *B) {
  __m256d A1_vec = _mm256_load_pd(A);
  __m256d B_vec = _mm256_broadcast_sd(B);
  __m256d C1_vec = A1_vec * B_vec;
  }
#endif

我将通过

编译这个test.c文件
gcc -fpic -O2 -c test.c

注意我没有打开 GCC 标志 -mfma,所以 #error 将被触发。我期望的是,在 GCC 看到这个 #error 之后,编译将 立即停止 ,但这是我在 GCC 5.3 中得到的结果:

test.c:14:2: error: #error "Please turn on GCC flag: -mfma"
 #error "Please turn on GCC flag: -mfma"
  ^
test.c: In function ‘foo’:
test.c:22:11: warning: AVX vector return without AVX enabled changes the ABI [-Wpsabi]
   __m256d A1_vec = _mm256_load_pd(A);
           ^

GCC 确实停止了,但为什么它也在 #error 之后接了一行?有什么解释吗?谢谢。


对于想要尝试的人来说,有一些硬件要求。您需要具有 AVX FMA 指令集的 x86-64。

我有一份 C ISO 规范的草稿副本,在 §4/4 中-它指出

The implementation shall not successfully translate a preprocessing translation unit containing a #error preprocessing directive unless it is part of a group skipped by conditional inclusion.

稍后,在 §6.10.5 中,#error 被正式定义,它说

A preprocessing directive of the form # error pp-tokens opt new-line causes the implementation to produce a diagnostic message that includes the specified sequence of preprocessing tokens.

换句话说,规范只要求任何具有#error的代码只需要编译失败并沿途报告错误消息,而不是编译需要立即终止#error 已达到。

考虑到始终在编译器报告的顶级错误之前检查编译器报告的顶级错误被认为是一种很好的做法,我想一个有能力的程序员看到一串以 #error 指令开头的错误会可能知道发生了什么。