CMake中多种C标准设置方式的差异及警告问题咨询
CMake中四种C标准设置方式的区别及警告差异分析
首先看你给出的CMake代码示例:
project(Test C) add_executable(test test.c) target_compile_features(test PRIVATE c_std_90) # (1) add_definitions(-std=c90) # (2) set (CMAKE_C_STANDARD 90) # (3) # 4a和4b功能等价 set_target_properties(test PROPERTIES C_STANDARD 90) # (4a) set_property(TARGET test PROPERTY C_STANDARD 90) # (4b) set_property(TARGET test PROPERTY C_STANDARD_REQUIRED ON) add_compile_options(-pedantic)
四种设置方式的核心区别
(1) target_compile_features(test PRIVATE c_std_90)
这是基于特性的标准控制,CMake不会直接向编译器传递-std=c90这类参数。它的核心逻辑是:检查目标代码是否仅使用了C90标准定义的编译特性,若代码用到了更高版本的特性(比如C99的long long),CMake会报错,但它不会强制编译器进入严格的C90模式——编译器可能仍处于默认的扩展兼容模式(比如GCC的gnu90),允许使用部分非标准扩展。
(2) add_definitions(-std=c90)
这是直接传递编译参数,本质是给所有编译目标添加-std=c90编译选项,强制编译器进入严格的C90标准模式。所有不符合C90的语法、特性都会被编译器标记,配合-pedantic会触发完整的标准合规警告。
(3) set(CMAKE_C_STANDARD 90)
这是全局默认标准设置,指定整个项目的默认C语言版本,但默认行为比较宽松:
- CMake不会主动传递
-std=c90,而是传递编译器的默认兼容模式参数(比如GCC的-std=gnu90),该模式允许使用编译器扩展(如long long); - 仅当同时设置
CMAKE_C_STANDARD_REQUIRED ON和CMAKE_C_EXTENSIONS OFF时,CMake才会传递严格的-std=c90参数,强制标准合规检查。
(4) set_target_properties / set_property 设置C_STANDARD 90
这两个写法功能完全等价,是针对单个目标的标准属性设置:
- 当配合
C_STANDARD_REQUIRED ON时,CMake会向目标传递严格的-std=c90参数,强制编译器进入C90标准模式; - 相比全局设置,它只作用于指定目标,不会影响项目内其他目标。
为什么测试代码的警告差异会出现?
你的测试代码使用了C99才引入的long long常量1ull和格式符%llu,不符合C90标准,但不同设置的行为不同:
#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello world! %llu", 1ull); return 0; }
(1)和(3)不触发警告:
- (1)的
target_compile_features只检查代码是否使用了C90不支持的编译特性,但不会强制编译器进入严格模式,编译器处于扩展兼容模式,允许long long这类语法; - (3)默认传递的是
-std=gnu90,该模式允许编译器扩展,所以不会触发-Wlong-long警告。
- (1)的
(2)和(4)触发警告:
- (2)直接传递
-std=c90,编译器进入严格C90模式; - (4)因设置了
C_STANDARD_REQUIRED ON,CMake传递了-std=c90,配合-pedantic选项,编译器会严格检查所有不符合C90的语法,因此触发use of C99 long long integer constant警告。
- (2)直接传递
内容的提问来源于stack exchange,提问作者hko
相关产品推荐
相关产品推荐

