1. extern用法
变量前有extern不一定就是声明,而变量前无extern就只能是定义。
注:定义要为变量分配内存空间;而声明不需要为变量分配内存空间。
https://www.runoob.com/w3cnote/extern-head-h-different.html
https://www.cnblogs.com/lanhaicode/p/10633125.htmlhttps://www.cnblogs.com/lanhaicode/p/10633125.html
简单总结:a.h 中extern声明,a.c中定义 ->b.h 中extern声明或者 添加头文件
2. __stdcall
__stdcall 是 Standard Call 的缩写,是 C++ 的标准调用方式:所有参数从右到左依次入栈,\
如果是调用类成员的话,最后一个入栈的是 this 指针。
3. 模式对话框(DoModal)和非模式对话框区别
1) 使用区别
模式对话框创建后,程序的其他窗口便不能进行操作,必须将该窗口关闭后,其他窗口才能进行操作。
而非模式对话框则无需这样,它不强制要求用户立即反应,而是与其他窗口同时接受用户操作。
2) 消息响应区别
3) 销毁的区别
模式对话框的销毁是使用EndDialog,而非模式对话框的销毁是使用DestroyWindow。
https://www.cnblogs.com/afarmer/archive/2012/03/31/2427328.html
4. m_hWnd句柄
m_hWnd句柄是类CWnd的第一个数据成员,凡是以CWnd派生的类定义的对象内部也都有这个句柄,
他是类或者对象标识自己的的句柄。
https://www.cnblogs.com/jack-jia-moonew/p/4236337.html
5. PostMessage(HWND,MSG,WPARAM,LPARAM)
https://blog.csdn.net/zebincai/article/details/9383625
6. GetDlgItem
是根据继承关系的函数功能,返回窗口中指定参数ID的子元素的句柄,可以通过返回的句柄对窗口内的子元素进行操作。
7. EnableWindow
使某个控件可用或不可用
8. C++模板
C++的模板提供了对逻辑结构相同的数据对象通用行为的定义。
这些模板运算对象的类型不是实际的数据类型,而是一种参数化的类型。
C++中的模板分为类模板和函数模板。
类模板:
template <class T>
class TClass
{
public:
// TClass的成员函数
private:
T DateMember;
};
函数模板:
template <class T>
T Max(const T a, const T b)
{
return a > b ? a : b;
}
模板特化:int float double 类型数值比较的问题
https://www.jianshu.com/p/4be97bf7a3b9
9. 字节序
大端字节序:高位字节在前,低位字节在后
小端字节序:低位字节在前,高位字节在后
https://www.ruanyifeng.com/blog/2016/11/byte-order.html
10. 字节对齐
数组 :按照基本数据类型对齐
联合 :按其包含的长度最大的数据类型对齐
结构体 :4字节或8字节对齐
更改C编译器的缺省字节对齐方式在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
一般地,可以通过下面的方法来改变缺省的对界条件:·
使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。·
使用伪指令#pragma pack (),取消自定义字节对齐方式。
另外,还有如下的一种方式:·
__attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。·
__attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
原则:
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
https://blog.csdn.net/21aspnet/article/details/6729724
结构体对齐疑问请看示例:
https://blog.csdn.net/shengabc/article/details/47777845
11. override关键字作用:
如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译。
12. explicit:防止构造函数隐式转换
13. 可重入函数
可重入函数可以简单地理解为: 函数可以在任意时刻被中断并再次被调用(即重入),稍后再继续执行被中断的那次调用,而不会丢失数据。
可重入函数的条件
不能含有静态(全局)非常量数据。
不能返回静态(全局)非常量数据的地址。
只能处理由调用者提供的数据。
不能依赖于单实例模式资源的锁。
调用的函数也必需是可重入的。
https://www.jianshu.com/p/2c8de98bf0db
14. VS解决方案的目录结构设置和管理
管理器(解决方案或项目)都会对应一个总的文件夹,这个管理器文件夹下存放本管理器的配置文件以及子管理器。比如,解决方案是个管理器,
它的文件夹下含有.sln配置文件以及子管理器ssyy项目和子管理器ssyy2项目。
默认情况下,项目属性设置的目录起点为项目配置文件所在位置,实际上就是项目头文件和源文件所在位置。
如果是C++项目,则解决方案总文件夹下就只包含解决方案配置文件sln和一个项目总文件夹和一个Debug文件夹以及一个Release文件夹
(共四个东东,其中Debug和Release文件夹中存放最终生成的结果exe或dll,要注意如果不使用Release生成,则不存在Release文件夹),
而项目总文件夹下包含C++源文件头文件、项目配置文件和一个Debug文件夹以及一个Release文件夹(一定要注意,此处的Debug和Release文件夹仅仅存放中间编译结果obj,
不存放exe和dll之类的东西。如果不使用Release编译,则没有对应的Release文件夹)。
默认情况下“输出目录”和“输出文件”两个属性对应的目录是一样的,这样用着方便(当然,输出文件的值在输出目录的值的基础上还包含有exe文件名)。
如果两个不一样,则中间生成的链接器用的如xx.ilk和xx.pdb文件等在输出目录,而最终生成的xx.exe文件在“输出文件”属性设置的目录中。
系统变量$(OutDir)的值由VS项目的“输出目录”属性决定,而$(TargetDir)和$(TargetPath)的值由VS项目的“输出文件”属性决定。即设置了VS的“输出目录”属性就相当于设置了$(OutDir)的值,
“输出目录”是界面上的提示用于接收用户输入的配置信息,然后把这个具体的配置信息存入系统内容的变量$(OutDir)中。
https://blog.csdn.net/weixin_41821317/article/details/107640638
https://blog.csdn.net/lp310018931/article/details/47991759
15. typedef void(*F)(int)理解
typedef void (*F) (int)定义了一个指向函数的指针F,其返回值 void 类型,参数是后面的(int).
然后我们就可以直接使用 F来定义这种指针变量,比如:F f; /*等价于void f(int);*/
16. 函数指针的形式:
形式1:返回类型(*函数名)(参数表)
#include <iostream>
using namespace std;
//定义一个函数指针pFUN,它指向一个返回类型为char,有一个整型的参数的函数
char (*pFun)(int);
//定义一个返回类型为char,参数为int的函数
//从指针层面上理解该函数,即函数的函数名实际上是一个指针,
//该指针指向函数在内存中的首地址
char glFun(int a)
{
cout << a;
//return a;
}
int main()
{
//将函数glFun的地址赋值给变量pFun
pFun = glFun;
//*pFun”显然是取pFun所指向地址的内容,当然也就是取出了函数glFun()的内容,然后给定参数为2。
(*pFun)(2);
return 0;
}
通过上面的一个小例子,我们知道了函数指针的用法,
而typedef可以让函数指针更直观方便
形式2:typedef 返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char glFun(int a){ return;}
void main()
{
pFun = glFun;
(*pFun)(2);
}
typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。
第二行的代码便使用这个新类型定义了变量pFun,此时就可以像使用形式1一样使用这个变量了。
17. strlen 返回计数器值(长度不包含'\0')
18. 数组指针与指针数组
数组指针:即指向数组的指针,如 int(*a)[4]
指针数组:用于存储指针的数组,也就是数组元素都是指针,如 int* a[4]
数组指针:
一般来说编译器会直接将数组转换为指针,即可以将数组名直接当作数组第一个成员的指针来使用。
指针数组;
由于指针也是对象,因此可以声明指针的数组,用来保存一列相同对象的集合。
定义指向int类型的指针的数组,其中[]优先级更高,即p为一个n维数组,其次为*,即为指针数组,最后为int,即为指向int类型的指针的数组。
结合数组指针的内容,可以将二位数组的每一行当作指针,则二维数组与指针的数组类似。
int *p[3];
int a[3][4];
for (int i = 0; i < 3; i++)
p[i] = a[i];
19. 回调函数使用类内的成员变量传入this指针,然后定义一个类的指针指向this
类中调用外部线程函数的方法
https://blog.csdn.net/xfortius/article/details/8454209
20. 线程pthread_join理解及分离退出
https://www.jianshu.com/p/a2ade02979d1
https://www.cnblogs.com/yiyide266/p/11227564.html
21. 注意格式
1) 尽量使用库中自带的宏
2) 主函数内的封装函数返回值为bool型助于判断
3) bool bRet = false;
do{ {... break;} bRet = true;} while(0);
if (!bRet) { ... }
4) close描述符或指针之后赋值
5) 打印日志靠近函数
6) 初始化、反初始化成对对应
7) 类构造初始化变量状态的判断及构造是否成功设置标志位
8) 销毁数据之前判断该数据的状态
9)变量命名要接近表示状态的意义
10)有新的变量时做判断
11)回调函数通过静态成员函数传入this指针,this指针调用普通成员函数实现对类内成员的操作
12)
22. select函数的使用
伪代码
...
while(true)
{
fd_set struFdSet;
FD_ZERO(stuFdSet);
FD_SET(listenfd, struFdSet)
maxfd = listenfd;
for (int i = 0; i < fdcount; ++i)
{
connectfd = fdsetarray[i];
if (connectfd > 0)
{
FD_SET(connectfd, strufdset);
maxfd = maxfd > connectfd ? maxfd : connectfd;
}
}
select(maxfd, &strufdset, ...)
if (FDISSET(listenfd, strufdset)))
{
connectfd = accept(listenfd)
for (int i = 0; i < fdset_size; ++i)
{
fdarray[i] = connectfd;
++fdcount;
break;
}
if (fdcount == fdset_size)
return;
}
else:
{
for (int i = 0; i < fdcount; i++)
{
connectfd = fdarray[i];
if (FDISSET(connectfd, strufdset))
{
read(connectfd);
FDCLR(connectfd, strufdset);
fdarray[i] = -1;
fdcount--;
...
}
}
}
...
}
23. scanf不阻塞问题,使用getchar()清空缓冲区
int iIn = -1;
if (scanf("%d", &iIn) != EOF)
{
while ((ch = getchar()) != '\n' && ch != EOF) {}
}
24. __stdcall,__cdecl,__pascal,__fastcall的区别
__cdecl
__cdecl 是 C Declaration 的缩写,表示 C 语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。
__stdcall
__stdcall 是 Standard Call 的缩写,是 C++ 的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是 this 指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X 表示参数占用的字节数,CPU 在 ret 之后自动弹出 X 个字节的堆栈空间,称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。
__pascal
__pascal 是 Pascal 语言(Delphi)的函数调用方式,也可以在 C/C++ 中使用,参数压栈顺序与前两者相反。返回时的清栈方式与 __stdcall 相同。
__fastcall
__fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此 __fastcall 通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同,返回方式和 __stdcall 相当。
__thiscall
__thiscall 是为了解决类成员调用中 this 指针传递而规定的。__thiscall 要求把 this 指针放在特定寄存器中,该寄存器由编译器决定。VC 使用 ecx,Borland 的 C++ 编译器使用 eax。返回方式和 __stdcall 相当。
__fastcall 和 __thiscall 涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以 Windows 上的 COM 对象接口都定义为 __stdcall 调用方式。
C 语言中不加说明默认函数为 __cdecl 方式(C中也只能用这种方式),C++ 也一样,但是默认的调用方式可以在 IDE 环境中设置。
25. C函数回调(callback)C++类成员函数的方法
https://www.jianshu.com/p/8b6de1e99fc2
类成员函数声明成static函数(回调函数需要一个地址)
传递对象
26. C++ 类的静态成员详细讲解
不能通过类名来调用类的非静态成员函数。
类的对象可以使用静态成员函数和非静态成员函数。
静态成员函数中不能引用非静态成员。
类的非静态成员函数可以调用用静态成员函数,但反之不能。
类的静态成员变量必须先初始化再使用。
https://blog.csdn.net/morewindows/article/details/6721430
27. python 文件读写模式r,r+,w,w+,a,a+的区别(附代码示例)
https://www.cnblogs.com/dadong616/p/6824859.html
28. 故意引发中断,判读位置
void intent_Assert()
{
#ifdef _DEBUG
char *p = NULL; //操作非法字符
*p = 1;
#endif
}
29. MFC字符集转换问题
如果是在unicode环境下:
CString a;
a.format(_T("%d*%d=%d\n"),a,b,a*b);
https://www.cnblogs.com/zCoderJoy/p/3425636.html