Cracking C++(9): 编译选项的设置

1. 目的

对应到 hackingcpp 网站上 Hello World 这一节内容的笔记和个人的拓展。

2. 生成 hello 可执行程序的过程

#include <iostream>
// our first program
int main ()
{
 std::cout << "Hello World\n";
}

C++ is a compiled language

source code can't be run directly
code is written to an abstract machine model (more on that later)
compiler translates source code into binary machine code understood by the CPU
program that can be run = binary executable file containing machine code

源代码(hello.cpp)经过预处理 -> 编译 -> 链接 的过程, 生成可执行文件。

在这里插入图片描述

3. 编译选项

作者给出的完整的编译命令是:

g++ -std=c++20 -Wall -Wextra -Wpedantic -Wshadow input.cpp -o output

并给出了解释:

-std=c++20 Sets compiler to the C++20 standard. Highly Recommended.

-Wall
-Wpedantic
-Wextra
-Wshadow

Enable compiler warnings. Highly recommended. These don’t really activate all warnings, but rather the most important ones that don’t produce too much (false positive) noise.

-o Sets the name of the output (executable) file.

个人推荐的命令则是:

clang++ -std=c++17 -fPIC -Wall input.cpp -o output

解释一下:

  • 个人推荐 Clang 胜过 GCC
  • 个人认为 C++20 在实际工作环境中,尤其是 adas 嵌入式环境、手机 NDK 开发环境中, 尤其要处理老代码时, 实际用的编译器版本未必支持 C++20,C++17 即可
  • -fPIC 没有被提到, 但是确是非常有必要的一个选项, 比如 Clang 编译的 gtest 要给 GCC 用, 不开 fPIC 会导致链接失败
  • -Wall 确实是一个容易被误会的选项,让人误以为 “treat all warning as error”, 但实际并不对应所有 warning
  • -Wpedentic, -Wextra, -Wshadow 看起来更安全了, 但是呢这远远不够, 推荐使用个人整理的 overlook 项目, 列出了30条左右的规则, 无论是写 C, 还是C++, 都能让你更安全

4. overlook 项目简介

4.1 基本用法

需要你的项目是基于 CMake 构建, 然后把 overlook.cmake 当插件一样使用

include(overlook.cmake)

然后, 按常规的编译步骤, 就可以了:

cd /path/to/your/project
cmake -S . -B build
cmake --build build # 执行编译

此时, 如果你的代码有不安全的地方, 编译器会自动报告出来。

4.2 典型例子: 函数缺少返回值

在 Android NDK 平台上, 如果函数函数返回值类型不是 void, 但是却没有返回值, 或者说有一条代码执行路径是没有返回值的, 编译器并不会报错。没错,不会报错!!

于是乎, 你编译的程序, 在手机运行时出现了 Crash, 看 Log 说是 “Trap”, 云里雾里。

实际上就是没有返回值导致的。编译器其实报告了一个 warning, 但如果你没注意到这条 warning, 就会遇到 Trap。既然这么重要的 warning 编译器并没有作为 error, 我们就主动把它作为 error, 没错, overlook 帮你做好了:

# Rule 4. 函数应该有返回值但没有 return 返回值;或不是所有路径都有返回值
# 解决bug:lane detect; vpdt for循环无法跳出(android输出trap); lane calib库读取到随机值导致获取非法格式asvl,开asan则表现为读取NULL指针
# -O3时输出内容和其他优化等级不一样(from 三老师)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  overlook_list_append(OVERLOOK_C_FLAGS /we4716 /we4715)
  overlook_list_append(OVERLOOK_CXX_FLAGS /we4716 /we4715)
else()
  overlook_list_append(OVERLOOK_C_FLAGS -Werror=return-type)
  overlook_list_append(OVERLOOK_CXX_FLAGS -Werror=return-type)
endif()

作为验证,请使用如下故意写bug的代码, 分别尝试不使用overlook和使用overlook的编译输出, 其中使用 overlook 后会编译报错,提前告知问题所在:

#include <stdio.h>

int print_data(int* data, int len)
{
    for (int i = 0; i < len; i++)
    {
        printf("%d ", data[i]);
    }
    printf("\n");
}

void example1()
{
    int data[10];
    for (int i = 0; i < 10; i++)
    {
        data[i] = i;
    }
    int res = print_data(data, 10);

    printf("res=%d\n", res);
}

//---------------------

int func1(int i)
{
    if (i)
        return 3; // C4715 warning, nothing returned if i == 0
}

void fatal()
{
}
int glue()
{
    if (0)
        return 1;
    else if (0)
        return 0;
    else
        fatal(); // C4715
}

void example2()
{
    func1(233);
    int qaq = glue();
    printf("%d\n", qaq);
}

//-----------------------------

int main()
{
    example1();
    example2();

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值