本文发自 http://www.binss.me/blog/the-problem-of-gcc4.8-when-using-the-c++11-regex-functionality/,转载请注明出处。
在使用C++11的新函数regex_match时,发现了一个奇怪的问题:
std::string s ("Accept: text/html");
std::regex e ("(.*): (.*)");
smatch sm;
regex_match(s, sm, e);
此段函数用于提取HTTP header中的name和value,在MAC下测试通过,sm在regex_match调用后size为3,符合预期:
- sm[0]为 Accept: text/html
- sm[1]为 Accept
- sm[2]为 text/html
结果在集成到HTTPServer后,执行结果与预期不匹配:
- sm[0]为 Accept: text/html
- sm[1]为 Accept: text/html
- sm[2]为 text/html
难道是我的正则表达式有误?掏出了多年以前的编译原理,研究了半天,好像并非如此。于是我尝试官方的例子:
int main()
{
std::string s ("subject");
std::regex e ("(sub)(.*)");
smatch sm;
regex_match(s, sm, e);
for (unsigned i=0; i<sm.size(); ++i)
{
std::cout << "[" << sm[i] << "] ";
}
cout<<endl;
}
官方文档中,输出为[subject] [sub] [ject],而在测试中,输出为[subject] [sub] [bject],这说明问题不是出在正则表达式上。于是我把目光投向了编译器:
$ g++ -v
Apple LLVM version 7.0.0 (clang-700.0.72)
而HTTPServer是放在ubuntu14.04的docker容器中编译的:
# g++ -v
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
果然不同,登录到gcc版本同是4.8.4的VPS上编译,得到了和HTTPServer相同的结果。
难道真的是编译器的锅,Google之:g++ 4.8 regex
结果发现了以下页面:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 http://stackoverflow.com/questions/23474121/what-part-of-regex-is-supported-by-gcc-4-9
Following information can be found from GCC 4.9 release notes:
"Support for various C++14 additions have been added to the C++ Front End, on the standard C++ library side the most important addition is support for the C++11 regex"
也就是说在4.9版本以前的实现regex不是我们在C++11文档中查到的那些,换言之,锅就是GCC的,解决的办法就是把GCC升级到4.9:
# apt-get install g++-4.9
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package g++-4.9
E: Couldn't find any package by regex 'g++-4.9'
果然找不到,因为好像昨天才执行过apt-get upgrade,继续Google之,网上说可以通过PPA来安装:
# apt-get install software-properties-common
# add-apt-repository ppa:ubuntu-toolchain-r/test
# apt-get update
# apt-get install gcc-4.9 g++-4.9
安装完成后,使用g++-4.9命令来编译:
# g++-4.9 -o test test.cpp -std=c++11
# ./test
[subject] [sub] [ject]
终于输出了预期的结果!
由于ppa的原因,我们的系统上如今存在两个版本的GCC,为了方便今后使用,将默认版本设置为4.9版本:
# update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
今后可以使用命令在两个版本间进行切换:
# update-alternatives --config gcc
There are 2 choices for the alternative gcc (providing /usr/bin/gcc).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/gcc-4.8 60 auto mode
1 /usr/bin/gcc-4.8 60 manual mode
* 2 /usr/bin/gcc-4.9 60 manual mode
输入数字即可切换到相应版本。