C/C++_notes
C/C++
Basic
- 常用文件
目标文件 | 可执行文件 | 静态库 | 动态库 | 常用库 | |
---|---|---|---|---|---|
Windows | .obj | .exe | .lib | .dll | |
Linux | .o | any | .a | .so | libc.so (标准C库); libm.so (标准C数学库) |
Compile & Link
gcc/g++
Default for Linux/Unix, mingw for windows
- files: .c -> .o -> .out
- Basic Examples
Compile: gcc -c a.c fun.c // -c Only Compiling, output a.out
Link: gcc -o a.out a.o func.o // -o output file name
Run: ./a.out
- Options:
-Wall // show all warnings
-O // optimization
- Library & Header
-l 添加库, m是libm.so这个动态函数库的缩写
-L 指定库文件路径, e.g. -L/lib -L/usr/lib
-I 指定头文件路径,e.g. -I/usr/include
msvc
cl.exe, Windows
- files: .c -> .obj -> .exe
clang
based on LLVM, iOS / OS X)
bcc
Borland C++: Borland
ICC
Intel
Library
BLAS/LAPACK, MKL, EIGEN
https://www.cnblogs.com/chest/p/11844129.html
Intel 相关的库文件
MKL的安装
https://www.cnblogs.com/Mayfly-nymph/p/11617651.html
MKL使用
- 如何查看静态库和动态库是32位还是64位
Windows 静态库和动态库
cd C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64
dumpbin /HEADERS xxx.lib
dumpbin /HEADERS xxx.dll
Linux静态库 objdump -a xxx.a
Linux动态库 file xxx.so
https://blog.csdn.net/fm0517/article/details/91803781?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
Syntax
Class 访问权限
public属性的成员可以被在对象外访问,protected和private成员只能在对象内访问
对象继承后的权限问题
public | protected | private | |
---|---|---|---|
公有继承 | public | protected | not access |
保护继承 | protected | protected | not access |
私有继承 | private | private | not access |
我的通俗理解:
一个人在快挂的时候把自己的财宝分成三份:
一份捐给社会(public,所有人都可以用)
一份留给儿子(protected,只有自己和儿子可以用)
一份自己带进棺材(private,只能自己用)
如果儿子比较正直(public inheritance),会这么接收财产:老爹捐给社会的那份依然捐给社会(public->public),老爹留给自己的那份以后会传给自己的儿子(protected->protected)
如果儿子虽自私但疼儿子(protected inheritance),会这么接收财产:老爹捐给社会的那份留给自己和儿子(public->protected),老爹留给儿子的那份也会传给儿子(protected->protected)
如果儿子非常自私(private inheritance),会这么接收财产:老爹捐出的和给自己的都只留给自己(public->private;protected->private)
ps,不管咋样,老爹带进棺材的那份,儿子都无法用
原创-类的成员函数
如果不考虑权限的问题, C++中类的成员函数, 其实就是被编译器改了个名字,对非静态的,又加了个this参数
(ps:this指针 只是每个非静态成员函数隐含的参数,参数传入不压栈,通过ECX传入函数 )
程序设计的模块化,可以通过提升编程语言的功能和设计精巧的数据结构来实现
虚函数
基类指针只能访问基类中的成员函数,不能访问派生类中的成员函数,这样就不能通过同一指针对一系列的对象实现一般化操作。
(ps:为了防止指针的误操作,C++语法规定,一种类型的指针不能指向另一种类型的变量,但有一个例外,允许一个基类的指针指向其派生类的对象。但是通过该指针也只能访问派生类中从基类继承来的公有成员,不能访问派生类中新增的成员,除非通过强制类型转换将基类的指针转换为派生类的指针,另外派生类的指针是不允许指向基类的对象的)。
为了解决这个问题,引入虚函数,虚函数通过一个精巧且常用的数据结构来实现。C++为每一个含有虚函数的类构造一个虚函数表(vtable),并为这个类增加一个成员变量(vptr),用来指向这个虚函数表。
虚函数表中的每一项为当前类中的虚函数名和对应的虚函数的地址。派生类会继承基类的虚函数表,如果在派生类中改写了一个虚函数,就会去改写虚函数表,将虚函数名对应的函数地址更新为当前的虚函数地址。程序执行时,基类指针根据虚函数表找到正确的函数地址。其实就是编译时在调用虚函数的地方不是直接给出函数地址,而是在执行的时候通过指向对象的虚函数表找到函数地址
(ps:纯虚函数:virual void func() = 0; 拥有纯虚函数的类叫抽象类,抽象类不能用来生成实例,只能被继承,如果被继承后仍没有改写所以纯虚函数,则仍为抽象类 )
(ps:以单一指令调用不同的函数,这叫多态(Polymorphism) 除了虚函数,多态还有函数重载和运算符重载两种形式,函数重载是依靠C++编译器对函数的命名方法来实现的,这是对C语言的一个改进 关于编译器的命名方法和命名空间的问题,再谈:)
成员函数的指针
关于成员函数的指针,又是一个比较特殊的问题,成员函数的指针和一般的函数指针不一样,普通的函数指针本质就是一个long型的变量,存储函数的起始地址,而类的成员函数的指针其实是个结构体,成员函数的指针不光要包含成员函数的地址,还要包含引用成员函数的对象的信息。下面给个成员函数指针用法的例子,
class A
{
public:
void ca_fun() {}
void ca_fun2()
{
void (CA::*fp)(); // 定义
fp = &CA::ca_fun; // 赋值
(this->*fp)(); //调用
}
};
PS:
编译器提供了几个新的操作符来支持成员函数指针操作:
\1) 操作符":😗"用来声明一个类成员函数指针,例如:
typedef void (Base::*PVVBASEMEMFUNC)(void); //Base is a class
\2) 操作符"->*"用来通过对象指针调用类成员函数指针,例如:
(pBase->*pVIBaseMemFunc)();
\3) 操作符".*"用来通过对象调用类成员函数指针,例如:
(baseObj.*pVIBaseMemFunc)();
函数调用约定
_cdecl __fastcall与 __stdcall,三者都是调用约定(Calling convention),它决定以下内容:
(1)由调用者还是被调用者把参数弹出栈,
(2)以及产生函数修饰名的方法,C和C++不一样
PS:至于参数的入栈顺序,C语言是从右到左,pascal是从左到右,与调用约定没有关系。
出栈参数清理
1、__stdcall:被调用的函数在返回前清理传送参数的内存栈,
VB一般使用的是stdcall调用约定;Windows的API中,一般使用的是stdcall约定
建议在不同语言间的调用中(如DLL)最好采用stdcall调用约定,因为它在语言间兼容性支持最好;
在Windef.h中有如下的定义:
#define CALLBACK __stdcall
#define WINAPI __stdcall
2、__cdecl是C和C++程序的缺省调用方式。由调用者清理传送参数的内存栈。如果函数被调用多次,那么产生的可执行文件大小就会比__stdcall方式产生的大。但是对于可变参数的函数(参数有默认值),就只能使用__cdecl的调用方式,因为被调用者不知道传入了多少的参数。 main(或WinMain)函数的调用约定必须是__cdecl,不允许更改;
3、__fastcall调用约定:和__stdcall的区别就是用ECX和EDX传送前两个双字(DWORD)或更小的参数
调用约定可以通过工程设置:Setting...\C/C++ \Code Generation项进行选择,缺省状态为__cdecl。
名字修饰约定
1、C编译时函数名修饰约定规则:
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个"@"符号和其参数的字节数,
格式为_functionname@number,
例如 :function(int a, int b),其修饰名为:_function@8
__cdecl调用约定仅在输出函数名前加上一个下划线前缀,
格式为_functionname。
__fastcall调用约定在输出函数名前加上一个"@"符号,后面也是一个"@"符号和其参数的字节数,
格式为@functionname@number。
2、C++编译时函数名修饰约定规则:
1)、以"?"标识函数名的开始,后跟函数名;
2)、函数名后面"@@YG"表示__stdcall方式;"@@YA"表示__cdecl方式";"@@YI"表示__fastcall方式;
3)、参数表以代号表示:
X--void ,D--char,E--unsigned char,F--short,H--int,I--unsigned int,
J--long,K--unsigned long,M--float,N--double,_N--bool,
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;
参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。
整个格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ"
例如
int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”
void Test2()-----“?Test2@@YGXXZ”//第1个X表示输出参数是void,第2个X表示输出参数是void
ps:
1、_beginthread需要__cdecl的线程函数地址,_beginthreadex和CreateThread需要__stdcall的线程函数地址。2、extern "C" _declspec(dllexport) int __cdecl Add(int a, int b);
typedef int (__cdecl*FunPointer)(int a, int b);
原创-类型识别和动态创建
所谓运行时的类型识别就是指对象能够动态(动态这个词是相对于静态而言的,就是指在程序运行的阶段,不光是在编译的阶段)地知道自己、自己的老爹、自己的爷爷到自己的老祖宗是谁,也就是能够通过一个叫IsKindOf()的成员函数知道一个类是不是它自己或者它的祖宗。
要实现这个功能,MFC在每个类的定义中中加入了一个静态的CRuntimeClass的结构体,并将所有的类的这个结构体连成一个链表,每个新加入的类的CRuntimeClass作为表头,这个结构体的成员变量记录了它自己的名字,并指向它的老爹,还指向链表中下一个节点。
在每个类的CRuntimeClass结构体中有两个指针,一个指向它的老爹,一个指向下一个节点。所以要实现类型识别,只要通过指向老爹的这条线就可以了。链表的这条线是为了动态创建。
动态创建是为了程序在运行时能够用同一方法创建一个指定的类的对象(类型识别是为了程序在运行是能够用同一方法判断一个指定的类是不是它的亲人),方法是在CRuntimeClass这个静态的结构体中添加了两个成员函数并給类添加了一个静态成员函数CreateObject(),这个CreateObject()就是用来new一个这个类的对象,而CRuntimeClass中添加的两个成员函数一个是CreateObject(),这个RuntimeClass的CreateObject()通过RuntimeClass中的一个指向类的CreateObject()函数的函数指针调用类的CreateObject()函数来新建对象, 另 一个RuntimeClass添加函数是静态的Load(),用来载入新建对象用的数据。
我们要创建某一个类的对象,只要遍历这个链表,找到这个类的CRuntimeClass,(注意,CRuntimeClass的结构体是静态的,只要定义了类,哪怕不生成实例,每个类的CRuntimeClass结构体也出生了) ,利用CRuntimeClass的成员函数来动态创建指定类的对象。
你有可能要问,我要创建一个对象,定义一个不就行了,别忘了,我要的是动态创建,你可能又要说,我可以直接new一个对象,可new一个对象的方法不能实现代码的通用化,在模块化设计的今天,通用化是非常重要的
友元函数
友元函数是某个类的朋友,它可以访问类的任何成员(包括private and protected);
友元函数不是它亲近的类的成员函数,它可以是一个普通的全局函数,也可以是另外一个类的成员函数。
友元函数由于不是亲近类的成员函数,因此没有this指针,访问非static对象时,友元函数的参数中肯定有一个是对象的引用或对象名。
友元也可以是一个类,该类被称为友元类,友元类所有成员函数都是友元函数
友元函数主要是用来提高程序的效率
class A
{
friend void printWidth( Box box ); // declare a friend function
friend class B; // declare B is a friend class
};
Others
MinGW / Cygwin / MSYS2
-
MinGW
Minimalist GNU for Windows,可在windows下使用 gcc/g++ 编译出 exe 文件。
安装: http://c.biancheng.net/view/8077.html -
Mingw-w64
新一代的 MinGW
下载 https://winlibs.com/
解压到 C:\mingw64
如果在matlab中使用,则新建环境变量 - 变量名:MW_MINGW64_LOC。变量值:C:\mingw64 -
Cygwin
在windows中,提供一个支持 POSIX 接口的开发环境
-
MSYS
类似Cygwin,比Cygwin精简 -
MSYS2
新一代的 MSYS。
Version
- C
1978 K&R C
* 1989 ANSI C
* 1999 C99
- C++
* 1998 C++98
2003 C++03
* 2011 C++11
2014 C++14
2017 C++17
https://www.cnblogs.com/hele-two/p/4512478.html?utm_source=tuicool&utm_medium=referral
- Visual Studio
名称 | 内部版本 | Visual C++ |
---|---|---|
Visual Studio | 4.0 | Visual C++ 4.0 |
Visual Studio 97 | 5.0 | Visual C++ 5.0 |
Visual Studio 6.0 | 6.0 | Visual C++ 6.0 |
Visual Studio .NET 2002 | 7.0 | Visual C++ 2002 |
Visual Studio .NET 2003 | 7.1 | Visual C++ 2003 |
Visual Studio 2005 | 8.0 | Visual C++ 2005 |
Visual Studio 2008 | 9.0 | Visual C++ 2008 |
Visual Studio 2010 | 10.0 | Visual C++ 2010 |
Visual Studio 2012 | 11.0 | Visual C++ 2012 |
Visual Studio 2013 | 12.0 | Visual C++ 2013 |
Visual Studio 2015 | 14.0 | Visual C++2015 |
Visual Studio 2017 | 15.0 | Visual C++ 2017 |
Visual Studio 2019 | 16.0 | Visual C++ 2019 |
JIT (Just In Time)
https://blog.csdn.net/qq_34902684/article/details/85538895?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/yayaayaya123/article/details/83993041
https://blog.csdn.net/sunboylife/article/details/88564369
OpenMP (Open Multi-Processing)
https://www.cnblogs.com/lfri/p/10111315.html
https://zhuanlan.zhihu.com/p/51173703