为什么我无法在 GCC 13.x 版本中使用 #pragma GCC target(...) 声明字符串类型变量

zyk*_*507 6 c++ gcc g++

我刚刚将 GCC 编译器版本从 11.4 更新到 13.1。我发现以下代码曾经在我的旧 GCC 11.4 上运行,但不再在 GCC 13.1 上运行。

#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")

#include <iostream>

int main() {
    std::string s = "Hello World!";
    std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这是编译器消息:

====================[ Build | run | Debug ]=====================================
"C:\Program Files\JetBrains\CLion 2023.3.2\bin\cmake\win\x64\bin\cmake.exe" --build C:\Users\zyk\CLionProjects\run\cmake-build-debug --target run -j 18
[1/2] Building CXX object CMakeFiles/run.dir/main.cpp.obj
FAILED: CMakeFiles/run.dir/main.cpp.obj 
C:\PROGRA~1\JETBRA~1\CLION2~1.2\bin\mingw\bin\G__~1.EXE   -g -fdiagnostics-color=always -MD -MT CMakeFiles/run.dir/main.cpp.obj -MF CMakeFiles\run.dir\main.cpp.obj.d -o CMakeFiles/run.dir/main.cpp.obj -c C:/Users/zyk/CLionProjects/run/main.cpp
In file included from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/string:43,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/locale_classes.h:40,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/ios_base.h:41,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/ios:44,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/ostream:40,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/iostream:41,
                 from C:/Users/zyk/CLionProjects/run/main.cpp:3:
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/allocator.h: In destructor 'std::__cxx11::basic_string<char>::_Alloc_hider::~_Alloc_hider()':
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/allocator.h:184:7: error: inlining failed in call to 'always_inline' 'std::allocator< <template-parameter-1-1> >::~allocator() noexcept [with _Tp = char]': target specific option mismatch
  184 |       ~allocator() _GLIBCXX_NOTHROW { }
      |       ^
In file included from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/string:54:
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/basic_string.h:192:14: note: called from here
  192 |       struct _Alloc_hider : allocator_type // TODO check __is_final
      |              ^~~~~~~~~~~~
ninja: build stopped: subcommand failed.
Run Code Online (Sandbox Code Playgroud)

通过删除#pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")甚至不声明任何字符串类型变量,我可以让代码再次工作。但有时由于某些原因我需要这行代码。

这是我在编译器资源管理器上的代码的链接:https://godbolt.org/z/r4rxr6Efn

UPD:更新了最小的工作示例,没有using namespace std;bit/stdc++.h文件。

nul*_*lly 5

更新了最小的工作示例,没有using namespace std;bit/stdc++.h文件。

我假设您来自竞争性编程社区,所以我将提供一个纯粹针对 codeforces、atcoder 等网站优化的答案,...)

“揭穿”最上面的答案:

否则,您尝试将target编译指示放在标准库函数上,但这是不受支持的。

这不是真的,这是 GCC 13 上的错误回归,已在GCC bugzilla上报告,后来在 codeforces 上重复。简而言之,always_inline构造函数上存在一个问题,它会阻止std::vectorstd::setstd::string等构造函数与#pragma GCC target. 虽然它在 GCC 版本 < 13 下运行多年,但效果非常好

切勿将其放在指令前面#include

引用自一篇经过深入研究的博客【教程】GCC Optimization Pragmas:请记住,为了优化程序的所有部分,所有 pragma 都必须出现在提交的开头,甚至在包含之前。所以,如果你想在有限的时间内完成一个问题,就不要听从上面的建议!

解决方案

幸运的是,大多数在线评委仍然保留旧的 GCC 版本,codeforces (GCC 11.2.0)例如atcoder (GCC 12.2)因此您不必担心提交这些代码后的编译错误。

这给我们留下了 3 种方法来在本地处理这个错误:

  • 最明显的解决方案是安装较旧的 gcc 版本(sudo apt install gcc-12yay -S gcc12),然后g++-12使用g++
  • 手动添加-m{target}编译标志,例如,如果您编写,#pragma GCC target("avx2,bmi2")您应该能够使用g++ sol.cpp -mavx2 -mbmi2
  • 大多数在线法官-DONLINE_JUDGE在他们的编译命令中都有(例如codeforces 命令atcoder 命令),所以让我们利用它来发挥我们的优势(或者,您也可以使用g++ sol.cpp -DLOCAL并将第一行更改为#ifndef LOCAL):
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#endif
#include <bits/stdc++.h>
using namespace std;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  string s = "Hello world!";
  cout << s << '\n';
}
Run Code Online (Sandbox Code Playgroud)

这样,您的代码将在最新的 GCC 版本上本地编译(不带编译指示)和在线判断(带编译指示)!