前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++雾中风景番外篇4:GCC升级二三事

C++雾中风景番外篇4:GCC升级二三事

作者头像
HappenLee
发布2020-02-24 12:36:43
7290
发布2020-02-24 12:36:43
举报

最近将手头上负责的项目代码从GCC 4.8.2升级到了GCC 8.2。(终于可以使用C++17了,想想后续的开发也是很美好啊~~)不过这个过程之中也遇到了一些稀奇古怪的问题,在这里做一个简单的记录,希望后续有同学遇到类似的问题能作为参考。

1. error: unable to find string literal operator 'operator"

这个我感觉是历史的遗留问题了,从C++11开始就不支持字符串字面量后面直接连接变量名,GCC 4.8.2应该是没有支持该编译检查,所以后续升级8.2的时候报了类似的错误。

听着有些抽象啊,举个栗子:

代码语言:javascript
复制
#define LOG(fmt, ...) printf("[%s][%s][%d]:"fmt "\n", __FILE__, __FUNCTION__,\
                            __LINE__, ##__VA_ARGS__)

上面是一段C++常用的日志宏定义,在宏定义展开的时候,编译器会默认将[%s][%s][%d]:,fmt,"\n"字面量拼接在一起,然后和后面行号等宏定义作为参赛打印出来。

代码语言:javascript
复制
#define LOG(fmt, ...) printf("[%s][%s][%d]:" fmt "\n", __FILE__, __FUNCTION__,\
                            __LINE__, ##__VA_ARGS__)
2. error: flexible array member not at end of struct

在C++之中,给定了一个结构定义和一个指向结构的指针,编译器必须能够通过指针偏移的方式访问该结构的任何成员。由于结构中每个成员的位置都取决于其前导成员的数量和类型,因此访问任何结构都需要知道所有前导成员的数量和类型。

在结构体之中,如果是数组为结构体之中最后的成员。这并不违反上述的编译规则。但是,如果flexible array member出现在了结构体末尾以外的任何位置,则其后的任意成员的位置都将取决于数组中对应的类型的个数,所以编译器禁止将没有定义长度的数组作为结构体的中间成员。

举个栗子:

代码语言:javascript
复制
struct S {
    int a;
    char b[];
    int c;
};

这里由于b成员的长度是不确定的,所以编译器无法通过S的指针推断出成员c的位置,所以编译报错:

b不在结构体S的末尾

而我们看如下的结构体就没有编译报错的问题了:

代码语言:javascript
复制
struct S {
    int a;
    int c;
    char d[];
};

看到这,可能有些读者会问了,如果我就是需要在结构体之中定义两个变长的数组,能怎么办呢? 笔者有觉得有下面两种方式实现:

  • 用指针啊!!!把结构定义为下面这种形式就可以了
代码语言:javascript
复制
struct S {
    int a;
    char b[0];
    int c;
    char d[];
};
  • 如果b和d成员长度一致或者不在内存损耗的情况,也可以采用如下方式来定义这个结构体:
代码语言:javascript
复制
struct Pair {
    char b;
    char d;
}
struct S {
    int a;
    int c;
    Pair p[];
};
3. 返回值的坑

有返回值的函数没有指定return,或是return了却没有给出返回值在gcc进行-O优化等级大于1时,会出现各种稀奇古怪的core。笔者也是通过GDB调试了很久,最终通过编译器的警告发现了上述的问题。

这个理论上是一个很低级的错误,但是笔者花了比较长的时间排查,因为出现的实在是有些诡异。

我们来看如下代码:

代码语言:javascript
复制
int test(int a, int b) {
    auto c = a + b;
}

int main() {
    auto c = test(10, 20);
    return 0;
}

上面我们可以看到test函数本身是需要返回一个int类似作为返回值的,但是这里并没有进行应有的返回。

上述代码在GCC 4.8.2之中并不会出现问题,但是一旦切换到GCC8.2之后,并且在编译优化等级大于1的时候,就会core在这个函数的执行代码位置。

所以为了规避上述的问题,笔者这里推荐使用GCC编译时开启编译选项:-Werror=return-type。这样,有上述返回值问题的代码就会在编译期间被编译器识别并报错。(其实参数-W,-Wall编译器是会对上述问题报警的,但是warning嘛,大家经常就不care啊~~~)

4.小结

简单总结了一下笔者升级GCC过程之中遇到的一些小的编译问题,希望可以帮助到同样问题的同学。GCC8.2也囊括了绝大多数C++17的新特性和部分的C++2a的特性,各种新的语法糖在编码过程之中也能极大的提高开发效率。Enjoy your modern CPP。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. error: unable to find string literal operator 'operator"
  • 2. error: flexible array member not at end of struct
  • 3. 返回值的坑
  • 4.小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档