C++笔记(二)

1. extern用法
    变量前有extern不一定就是声明,而变量前无extern就只能是定义。
    注:定义要为变量分配内存空间;而声明不需要为变量分配内存空间。
https://www.runoob.com/w3cnote/extern-head-h-different.html

https://www.cnblogs.com/lanhaicode/p/10633125.htmlicon-default.png?t=M5H6https://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
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值