c++ - 使用 gcc 而不是 g++ 输出二进制文件的大小更小
问题描述
我正在将我的项目从 C 迁移到 C++,今天我注意到了一些奇怪的事情。我有两个几乎相同(唯一的区别是 .cpp 中的 extern 关键字)主文件(为编译测试目的而创建)。第一个是 main.c,第二个是 main.cpp。
您可以在下面找到这些文件的源代码。我使用的是libopencm3,它编译成静态库,然后在需要的地方链接。那么问题是什么?在我使用 main.c(使用 gcc)编译项目的场景中,输出二进制文件比使用 main.cpp(使用 g++)编译生成的输出二进制文件小得多。我无法弄清楚是什么导致了这个问题?
该代码是为 STM32F1C8T6 目标编译的。
//main.c
#include <libopencm3/stm32/rcc.h>
static void rcc_setup()
{
//Clock setup
rcc_clock_setup_in_hse_8mhz_out_72mhz();
//Peripherals clock
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
}
int main()
{
rcc_setup();
while(1)
{
}
}
//main.cpp
extern "C" {
#include <libopencm3/stm32/rcc.h>
}
static void rcc_setup()
{
//Clock setup
rcc_clock_setup_in_hse_8mhz_out_72mhz();
//Peripherals clock
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
}
int main()
{
rcc_setup();
while(1)
{
}
}
我的项目的结构基本上是这样的:
- root
CMakeLists.txt
- lib
- libopencm3
- src
- app
CMakeLists.txt
- inc
- src
- main.c
- main.cpp
这是我的根 CMakeFile.txt。我认为它是最重要的,因为它包含编译标志等。其中还有一些其他的东西,比如端口目录、port.cmake 等,但在这种情况下这些并不重要,所以请忽略它们。
cmake_minimum_required(VERSION 3.16)
project(stm32-template)
# COMPILER JUST TEMPORARY TODO: REMOVE!!!
set(CMAKE_ASM_COMPILER "/usr/bin/arm-none-eabi-gcc")
set(CMAKE_C_COMPILER "/usr/bin/arm-none-eabi-gcc")
set(CMAKE_CXX_COMPILER "/usr/bin/arm-none-eabi-g++")
# CMAKE MODULES
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
# GENERAL PATHS
set(PORT_DIR ${PROJECT_SOURCE_DIR}/src/port/${PORT})
# PORT CONFIGURATIOM
include(${PORT_DIR}/port.cmake)
# COMPILER CONFIGURATION
set(COMPILER_CXX_FLAGS "-fno-use-cxa-atexit -Os")
set(COMPILER_FLAGS "-fdata-sections -ffunction-sections -O0 -DNDEBUG -Werror")
set(LINKER_FLAGS "-nostartfiles -specs=nano.specs -specs=nosys.specs --static -ggdb3 -Wl,--gc-sections -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group -Wl,-Map=output.map -T ${LD_SCRIPT}")
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_C_FLAGS "${COMPILER_FLAGS} ")
set(CMAKE_CXX_FLAGS "${COMPILER_CXX_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
# LIBRARIES
set(LIBOPENCM3_PATH ${PROJECT_SOURCE_DIR}/lib/libopencm3)
set(LIBOPENCM3_INCLUDE ${LIBOPENCM3_PATH}/include)
set(LIBOPENCM3_BIN ${LIBOPENCM3_PATH}/lib/libopencm3_${MCU_FAMILY}.a)
ExternalProject_Add(libopencm3
SOURCE_DIR "${LIBOPENCM3_PATH}"
BUILD_IN_SOURCE true
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
BUILD_COMMAND make
)
# ADD LIBRARY INCLUDES
include_directories(${LIBOPENCM3_INCLUDE})
# SUBDIRECTORIS
add_subdirectory(src)
# CUSTOM COMMANDS
add_custom_target(flash
COMMAND JLinkExe -device STM32F103C8 -If SWD -Speed 1000 -CommandFile tools/jlink/FlashCommand.jlink
COMMENT "asd"
#DEPENDS {EXE_NAME}
)
解决方案
C++ 语言的运行时间比 C 语言大得多(因为异常、RTTI、...<iostream>
等<thread>
)。
当您静态链接应用程序时,您会链接整个语言运行时,或者至少链接代码中某处引用的那些部分,包括您拉入的标头中的静态对象和线程本地存储持续时间(例如 std::cout )。大多数桌面应用程序看不到这一点,因为它往往在 DSO 中。
由于语言互操作,您会发现大量 C++ 运行时实际上在您的系统 libc 中。这包括异常处理和展开。如果您看到像 __cxa_* 和Unwind * 这样的符号,那就是发生了什么。
推荐阅读
- javascript - @testing-library/react (rtl) 'waitFor' 只有在没有 await 关键字的情况下才会成功
- reactjs - 在 React 中单击时更改特定按钮的文本
- android - Audio Focus 在 android 9 和 android 10 android 中不起作用?
- linux - 为什么从 666 而不是 777 中减去文件的 umask?
- r - 使用“dplyr”计算每一行数据帧的特定比率
- java - 如何停止片段之间的交易?
- node.js - 带有 React 和 Express 的 Socket IO。ReactJS 错误:无法代理请求 /socket.io/?EIO=4..... 从 localhost:3000 到 http://127.0.0.1:4000
- javascript - 在javascript中将网格重新缩放到移动屏幕
- android - AAPT:错误:未绑定的前缀。在 XML 安卓中
- python - 如何将此形状划分为一个单元(例如 1x1),如网格?