C++11 与 C99的兼容

2023-10-11 05:08
文章标签 c++ 兼容 c99

本文主要是介绍C++11 与 C99的兼容,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++对以下C99特性的支持纳入了新标准之中:
1、C99中的预定义宏
2、__func__预定义标识符
3、_Pragma操作符
4、不定参数宏定义以及__VA_ARGS__
5、宽窄字符串连接



1> c++11中与c99兼容的宏如下表所示:


使用上述宏可以检查机器环境对C标准和C库的支持情况。
#include <iostream>
using namespace std;int main()
{cout << "Standerd Clib" << __STDC_HOSTED__ << endl;cout << "Standerd C" << __STDC__ << endl;//cout << "C Standerd version " << __STDC_VERSION__ << endl;//cout << "ISO/IEC" << __STDC_ISO_10646__ << endl;return 0;
}
在g++ 2.3.3版本中后面两行不能编译通过,说明在g++ 2.3.3版本中可能没有给出这两个宏的定义。

2> __func__预定义标识符

很多现实的编译器都支持C99标准中的__func__预定义标识符功能,其基本功能就是返回所在函数的名字。
#include <iostream>
using namespace std;const char* hello()
{return __func__;
}const char* world()
{return __func__;
}int main()
{cout << hello() << world() << endl;return 0;
}

Tips: vs2012中不支持,g++ 3.3.2版本支持,这个版本的g++还不支持C++11标准。所以这是兼容C99标准。

__func__在按照标准定义,编译器会隐式地在函数定义后面定义__func__标识符。

const char* hello()
{static const char* __func__ = "hello";renturn __func__;
}

在C++11标准中,还允许在类和结构体中使用这个宏。
#include <iostream>
using namespace std;struct TestStruct
{TestStruct(): name(__func__){}const char* name;
};int main()
{TestStruct ts;cout << ts.name << endl;renturn 0;
}

但是将__func__标识符作为函数参数的默认值是不允许的。
void FuncFail(string func_name = __func__){};  //编译不能通过



3>_Pragma操作符

在C/C++标准中,#pragma是一条预处理指令。


#pragma once

上述代码和
#ifndef THIS_HEADER
#define THIS_HEADER//一些头文件定义#endif

C++11中定义一个_Pragma操作符和#pragma作用相同。_Pragma操作符的格式如下:
_Pragma(字符串字面量)
使用_Pragma操作符想要达到#pragma once的效果可以:
_Pragma("once")


4>变长参数的宏定义以及__VA_ARGS__

在C99标准中,程序员可以使用变长参数的宏定义。变长参数的宏定义是指在宏定义中参数列表的最后一个参数为省略号,而预定义宏__VA_ARGS__则可以在宏定义的实现部分替换省略号所代表的字符串。
#define PR(...) printf(__VA__ARGS__)
就可以定义一个printf的别名PR。事实上,变长参数宏和printf是一对好搭档。

#include <stdio.h>#define LOG(...) {\fprintf(stderr,"%S:Line %d:\t"), __FILE__, __LINE__};\fprintf(stderr,__VA__ARGS__);\fprintf(stderr,"\n");\
}int main()
{int x=3;LOG("x=%d",x);
}

上述例子在vs2012中不支持,在g++ 3.3.2版本支持


5>宽窄字符串连接

在C++11中,在将窄字符串和宽字符串进行连接时,支持C++11标准的编译器会将窄字符串转换成宽字符串,然后再与宽字符串进行连接。


6、扩展的整型
C++11中一共只定义了5种标准的有符号整型:
signed char
short int
int
long int
long long int

标准同时规定,每一种有符号整型都有一种对应的无符号整型版本,而且有符号整型与其对应的无符号整型具有相同的存储空间大小。



7、宏__cplusplus
在C/C++混合编写的代码中,我们经常会在头文件中看到如下的声明:

#ifdef __cplusplus
extern "C"{
#endif
//一些代码
#ifdef __cplusplus
}
#endif
由于extern "C"可以抑制C++对函数名、变量名等符号进行名称重整(name mangling),因此编译出的C目标文件中的变量,函数名称等等符号都是相同的,连接器可以
可靠的对两种类型的目标文件进行连接,这样该做法成为C与C++混用头文件的典型做法。
tips:在C++03标准中,__cplusplus的值被预定为199711L,在C++11中,宏__cplusplus被预定义成201103L。那么可以利用这个宏来检查编译器是否支持C++11新标准。


#if __cplusplus < 20131103L#error "should use C++ 11 implementation"
#endif

这里,使用了预处理指令#error,使得不支持C++11时,编译报错并且终止编译。

3、断言assert
assert是一种边编程中常用的手段。用于排除在逻辑上不应该产生的情况。在C++中标准在<cassert>或者<assert.h>头文件中为程序员提供了assert宏,用于在运行时进行断言。


#include <cassert>using namespace std;double div(double a,double b)
{assert(b != 0.000000);  //断言除数必须不为零return a/b;
}int main()
{double rt = div(10,0);return 0;
}

static_assert在C++11中定义了一个static_assert,这个声明对于模板的调试非常有用,编译器快速执行这个常量表示式参数(不能依赖模板参数)。否则编译器当模板实例化时执行这个常量表达式的参数。

#include <cassert>
#include <cstring>
using namespace std;template<typename t, typename u>
int bit_copy(t& a, u& b)
{static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have same width.");
};int main() {int a = 0x2468;double b;bit_copy(a,b);return 0;
}

在编译的过程中就会出现如下的错误信息:






这篇关于C++11 与 C99的兼容的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/185728

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.

C++多线程开发环境配置方法

《C++多线程开发环境配置方法》文章详细介绍了如何在Windows上安装MinGW-w64和VSCode,并配置环境变量和编译任务,使用VSCode创建一个C++多线程测试项目,并通过配置tasks.... 目录下载安装 MinGW-w64下载安装VS code创建测试项目配置编译任务创建 tasks.js

C++ 多态性实战之何时使用 virtual 和 override的问题解析

《C++多态性实战之何时使用virtual和override的问题解析》在面向对象编程中,多态是一个核心概念,很多开发者在遇到override编译错误时,不清楚是否需要将基类函数声明为virt... 目录C++ 多态性实战:何时使用 virtual 和 override?引言问题场景判断是否需要多态的三个关

C++简单日志系统实现代码示例

《C++简单日志系统实现代码示例》日志系统是成熟软件中的一个重要组成部分,其记录软件的使用和运行行为,方便事后进行故障分析、数据统计等,:本文主要介绍C++简单日志系统实现的相关资料,文中通过代码... 目录前言Util.hppLevel.hppLogMsg.hppFormat.hppSink.hppBuf