《C++文章汇总》
上一篇文章介绍了《01-Cin、Cout、函数重载和默认参数》,本文介绍Extern、内联函数Inline和Const。
1.被extern "C"修饰的代码会按照C语言的方式去编译
两种写法,一种是加载头部,另一种是用大括号包住
I.加在头部extern "C"
#include
using namespace std;
extern "C" void func(){
}
extern "C" void func(int v1){
}
int main(int argc, const char * argv[]) {
getchar();
return 0;
}
//报错,不允许重载,C语言不支持重载
II.大括号包住
extern "C" {
void func(){
}
void func(int v1){
}
}
2.如果函数同时有声明和实现,要让函数声明被extern "C"修饰,函数实现可以不修饰,声明和实现同时修饰也不会报错
extern "C" void func();
extern "C" void func0(int v1);
int main(int argc, const char * argv[]) {
getchar();
return 0;
}
extern "C" void func(){
}
extern "C" void func0(int v1){
}
extern "C"也可以用来包住声明头部
extern "C" {
void func();
void func0(int v1);
}
int main(int argc, const char * argv[]) {
getchar();
return 0;
}
extern "C" void func(){
}
extern "C" void func0(int v1){
}
由于C、C++编译规则的不同,在C、C++混合开发时,可能会经常出现以下操作
C++在调用C语言API时,需要使用extern "C"修饰C语言的函数声明
#include "main.h"
int sum(int v1,int v2){
return v1 + v2;
}
int sub(int v1,int v2){
return v1 - v2;
}
extern "C" {
int sum(int v1,int v2);
int sub(int v1,int v2);
}
int main(int argc, const char * argv[]) {
cout << sum(10, 20) << endl;
cout << sub(30, 20) << endl;
getchar();
return 0;
}
新建头文件如main.h存放函数的声明,在要调用的类中引用
extern "C" {
#include "main.h"
}
int main(int argc, const char * argv[]) {
cout << sum(10, 20) << endl;
cout << sub(30, 20) << endl;
cout << divide(30, 2) << endl;
getchar();
return 0;
}
也可直接在头文件中指定,C++文件中默认定义了宏#define __plusplus在文件的第一句,在C文件中通过宏定义环境判断
#ifdef __cplusplus
extern "C" {
#endif
int sum(int v1,int v2);
int sub(int v1,int v2);
int divide(int v1,int v2);
#ifdef __cplusplus
}
#include "main.h"
int main(void) {
cout << sum(10, 20) << endl;
cout << sub(30, 20) << endl;
cout << divide(30, 2) << endl;
getchar();
return 0;
}
C文件调用C文件,C文件中也可以用宏定义判断
#include "main.h"
extern "C" {
#include "other.h"
}
int main(void) {
other();
cout << sum(10, 20) << endl;
cout << sub(30, 20) << endl;
cout << divide(30, 2) << endl;
getchar();
return 0;
}
//输出
other - 30
30
10
15
3.防止重复引入头文件,重复引入也没用了,后面的代码也不会执行了,因为#ifndef other_h表示没有定义,才会定义往下执行,第二次头文件引入时,已经定义了宏other_h,不会再往下执行,也可以大写,前面加两个__,比如__OTHER_H,保证宏名不一样,这样多个头文件引入的时候不会相互影响
#ifndef other_h
#define other_h
#include
void other();
#endif /* other_h */
#ifndef main_h
#define main_h
#include
#ifdef __cplusplus
extern "C" {
#endif
int sum(int v1,int v2);
int sub(int v1,int v2);
int divide(int v1,int v2);
#ifdef __cplusplus
}
#endif
#endif
在新文件中能同事包含
#include "main.h"
#include "other.h"
4.我们经常使用#ifndef、#define、#endif来防止头文件的内容被重复包含,#pragma once可以防止整个文件的内容被重复包含
pragram once也可以防止重复包含,引入了很多次头文件保证只引入了一次
区别
I.ifndef、#define、#endif受C\C++标准的支持,不受编译器的任何限制
II.有些编译器不支持#pragma once(较老编译器不支持,如GCC 3.4版本之前),兼容性不够好
III.#ifndef、#define、#endif可以针对一个文件中的部分代码,而#pragma once只能针对整个文件
5.内联函数
- 使用inline修饰函数的声明或者实现,可以使其变成内联函数
- 建议声明和实现都增加inline修饰
特点:编译器会将函数调用直接展开为函数体代码,可以减少函数调用的开销,会增大代码体积
- 什么时候使用内联函数?
1.函数代码体积不大
2.频繁调用的函数
- 递归的调用添加Inline意义不大,编译器会识别,内联不起作用,还是存在函数调用
- 注意
尽量不要内联超过10行代码的函数 有些函数即使声明为inline,也不一定会被编译器内联,比如递归函数
#include
using namespace std;
//开辟栈空间
void func(){
cout << "void func1()" << endl;
cout << "void func2()" << endl;
cout << "void func3()" << endl;
}//回收栈空间
int sum(int v1,int v2){
return v1+v2;
}
inline void func0(){
cout << "void func1()" << endl;
cout << "void func2()" << endl;
cout << "void func3()" << endl;
}
int sum0(int v1,int v2){
return v1+v2;
}
int main(int argc, const char * argv[]) {
func0();
cout << sum0(10, 20) << endl;
func();
cout << sum(10, 20) << endl;
return 0;
}
//输出
void func1()
void func2()
void func3()
30
void func1()
void func2()
void func3()
30
6.内联函数与宏
内联函数和宏,都可以减少函数调用的开销
对比宏,内联函数多了语法检测和函数特性
- 思考以下代码的区别
define sum(x) (x + x)
- inline int sum(int x) { return x + x; }
- int a = 10; sum(a++);
7.C++的有些表达式是可以被赋值的
int a = 1;
int b = 2;
//赋值给了a
(a = b) = 3;
//赋值给了b
(a < b ? a : b) = 4;
8.Const
◼ const是常量的意思,被其修饰的变量不可修改 如果修饰的是类、结构体(的指针),其成员也不可以更改
#include
using namespace std;
struct Date {
int year;
int month;
int day;
};
int main(int argc, const char * argv[]) {
/*
const Date d = {2011,2,5};
Date d2 = {2013,4,8};
d = d2;
d.year = 2018;
*/
Date d1 = {2011,2,5};
Date d2 = {2013,4,8};
const Date *p = &d1;
p->year = 2019;
(*p).month = 5;
*p = d2;
cout << d1.year << endl;
return 0;
}
//会报错,通过指针也无法修改了
◼ 以下5个指针分别是什么含义?
int age = 10;
int height = 30;
//p1不是常量,*p1是常量
const int *p1 = &age;
//p2不是常量,*p2是常量
int const *p2 = &age;
//p3是常量,*p3不是常量
int * const p3 = &age;
//p4是常量,*p4也是常量
const int * const p4 = &age;
//p5是常量,*p5也是常量
int const * const p5 = &age;
*p4 = 20;//age = 20;
p4 = &height;
*p4 = 40;//height = 40;
◼ 上面的指针问题可以用以下结论来解决:
const修饰的是其右边的内容
pStu1->age = 30也是想修改指针变量pStu1指向的内容,但指针变量*pStu1为常量,不能被修改,会报错