北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

C与C++混合使用存在的C99标准宏冲突与解决

作为C语言的老大哥——C++语言,伴随着C语言的成长而不断发展。即使到2025年的今天,C与C++混合使用的场景还是数不胜数。这不,一场C与C++混合使用而导致的C99标准宏冲突,就这样在不经意间发生。

一、背景

代码cpp.cpp在正常编译通过的情况下,在首行代码处插入一个新的标准C头文件c.h,c.h头文件就是包含了常用的C头文件,以及定义了一些公开接口,没有什么特别。然后再编译A.cpp,结果编译失败,提示代码中的SIZE_MAX找不到。

二、问题分析

代码中的SIZE_MAX是C99标准定义的宏,在stdint.h头文件中定义,详细如下:

#if !defined __cplusplus || defined __STDC_LIMIT_MACROS

……

# if __WORDSIZE == 64

# define SIZE_MAX (18446744073709551615UL)

# else

# define SIZE_MAX (4294967295UL)

# endif

# endif

……

#endif

cstdint头文件中关于stdint.h头文件的包含代码详细如下:

#if _GLIBCXX_HAVE_STDINT_H

# ifndef __STDC_LIMIT_MACROS

# define _UNDEF__STDC_LIMIT_MACROS

# define __STDC_LIMIT_MACROS

# endif

# ifndef __STDC_CONSTANT_MACROS

# define _UNDEF__STDC_CONSTANT_MACROS

# define __STDC_CONSTANT_MACROS

# endif

# include <stdint.h>

# ifdef _UNDEF__STDC_LIMIT_MACROS

# undef __STDC_LIMIT_MACROS

# undef _UNDEF__STDC_LIMIT_MACROS

# endif

# ifdef _UNDEF__STDC_CONSTANT_MACROS

# undef __STDC_CONSTANT_MACROS

# undef _UNDEF__STDC_CONSTANT_MACROS

# endif

#endif

c.h包含了头文件stdint.h,cpp.cpp包含了cpp.h,而cpp.h包含了cstdint。如果将c.h的位置移到cpp.h后面,则编译正常。

通过查看stdint.h头文件,定义SIZE_MAX有两个条件:其一是C代码,而cpp.cpp是C++代码,不满足该条件;其二是定义了宏__STDC_LIMIT_MACROS,而cpp.cpp首行包含c.h的情况下,实际先包含stdint.h头文件,此时未定义该宏而导致SIZE_MAX未定义,再次包含cpp.h而间接包含cstdint头文件时,由于stdint.h头文件前期已经被包含而导致二次包含时自动忽略,最终未定义宏__STDC_LIMIT_MACROS而导致代码编译报错。

如果将c.h位置移到cpp.h后面,由于先包含cstdint,所以会定义__STDC_LIMIT_MACROS宏,接着在包含stdint.h头文件时因为该宏的定义而定义SIZE_MAX宏,所以代码编译正常。

对于上述的分析,可以通过简单的一行代码进行对应测试验证,具体如下:

cat c.cpp

#include <stdint.h>


cat cpp.cpp

#include <cstdint>


g++ c.cpp -E -dD|grep SIZE_MAX

#define __SIZE_MAX__ (18446744073709551615UL)


g++ cpp.cpp -E -dD|grep SIZE_MAX

#define __SIZE_MAX__ (18446744073709551615UL)

#define SIZE_MAX (18446744073709551615UL)

其中,-E参数让编译器在预处理阶段之后停止,不进行编译、汇编和链接。输出的是预处理后的源代码(通常是.i文件或直接输出到标准输出)。-dD参数在预处理器的输出中,将所有的宏定义(包括预定义和用户定义的)以#define指令的形式输出。注意,这个选项会将宏定义插入到输出代码中对应的位置(或者按某种顺序输出)。

三、问题解决

对于C++使用C头文件的混用场景,只有一种办法实现最小化改动支持,那就是在c.h的头文件开始处(包含stdint.h头文件之前,最好在所有包含头文件之前,因为有些头文件内部会自动交叉包含)增加如下宏定义:

#ifndef __STDC_LIMIT_MACROS

#define __STDC_LIMIT_MACROS

#endif

是的,你没有看错,我们手动定义__STDC_LIMIT_MACROS宏。按照stdint.h和cstdint头文件的说明,都能够确保最终包含stdint.h头文件中SIZE_MAX宏被定义。

四、联系

如果有任何疑问欢迎随时联系交流!

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言