zoukankan      html  css  js  c++  java
  • 项目之MFC/VC++疑问巩固1

    2019年4月29日22:20:24

    1.#define

    参考:#define_百度百科
    在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为"宏"。字符串取代宏名。简单代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
    宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换

    一般形式为:
    #define 标识符 字符串

    带参宏定义的一般形式为:
    #define 宏名(形参表) 字符串

    #define 条件编译

    #define PI 3.1415926
    #define MAX(a,b) (a>b)?a:b
    在用#define 定义时 ,可以用斜杠("") 续行.与vb中的下划线(" _")作用同.
    比如:
    #define add1( x, y ) ( x + y)
    也可以表示成 :
    #define add1(x,y)
    (x + y )
    -------------------------------------------------------------------------------------
    const ~ # define比较
    条款1:尽量用const和inline而不用#define http://www.kuqin.com/effectivec2e/ch00b.htm
    在c++中从来就是建议能用const的地方不用define
    define在编译期间不做类型检查,只进行字符替换,并且在字符替换时可能会产生意料不到的错误。
    #define优点: 可以配合#ifdef等其它的宏和编译器的参数(如gcc的-D)方便地控制版本,控制哪部分代码只对调试有用,发布时自动把它去掉,而不用对高度好的代码做任何修改。这是const不具备的。
    #define可以定义函数,并且自动就是内联函数,运行时没有函数调用的开销,速度快。
      在可移植性代码中,#define用的非常多。它能根据当前环境决定哪部分代码用于这个平台,不适用于这个平台的代码可以由它控制而不让编译。
      在代码需要不同的编译器分别编译时,由于用#define可以避免各编译器因支持的语法差异而带来的错误。如:有些编译器不支持inline关键字,那么#define可以通过设置一个变量来控制对inline的处理。其它比如try catch等,为防止有些编译器不支持,标准库就是这么控制的。
      在动态链接库方面,C和C++处理方式不同,为了能够使C/C++混合编程成为可能,库文件中也是通过#define控制的。比如:#ifdef __cplusplus。。。。表明下面的代码用C++编译器处理,否则用C编译器去处理。

    1. typedef

    参考:typedef_百度百科
    typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明
    ---eg:
    typedef int size;// 为现有类型int创建别名
    size array[4];
    ---eg:
    typedef char Line[81];// Line类型即代表了具有81个元素的字符数组
    Line text,line;
    ---eg:
    typedef char* pstr;// 隐藏指针语法
    int mystrcmp(const pstr p1,const pstr p3);
    ---eg:
    typedef struct tagNode
    {
      char* pItem;
      struct tagNode* pNext;
    }*pNode;
    ---eg:
    struct tagMyStruct
    {
      int iNum;
      long lLength;
    };
    可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。
    typedef为这个新的结构起了一个名字,叫MyStruct:typedef struct tagMyStruct MyStruct;
    typedef 与 #define的问题
    typedef char* pStr1;//有分号
    #define pStr2 char* //无分号
    pStr1 s1,s2;
    pStr2 s3,s4;
    在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字
    在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,如:
    #define f(x) ((x)*(x))
    1) #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。
    2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。

    2. 条件编译

    选择性编译,为了让程序在各种不同的软硬件环境下都以运行。提高程序的可移植性和灵活性。同一段代码,针对不同的环境,预编译成不同代码,从而使得生成的程序最大程度上适应用户的软硬件环境。
    参考:条件编译_百度百科
    …………
    if格式
    #if 表达式

    [#else
    ]
    #endif
    功能:当表达式的值为真时,编译①,否则编译②。其中,#else和②可有可无。
    …………
    ifdef格式
    #ifdef 标识符

    [#else
    ]
    #endif
    功能:当标识符已被定义时(用#define定义),编译①,否则编译②。其中#else和②可有可无。
    …………
    ifndef格式
    #ifndef 标识符

    [#else
    ]
    #endif
    功能:当标识符未被定义时(用#define定义),编译①,否则编译②。

    3. #ifdef __cplusplus

    参考:#ifdef __cplusplus 倒底是什么意思?
    #ifdef __cplusplus
    extern "C" {
      #endif
      //一段代码
      #ifdef __cplusplus
    }
    #endif
    __cplusplus是cpp中的自定义宏:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。
    C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。

    4. __declspec(dllexport)和__declspec(dllimport)

    参考:__declspec(dllimport)的作用__declspec(dllimport) Windows C++中__declspec(dllexport)的使用
    动态链接库(DLL,Dynamic Link Library)。dllimport是为了更好的处理类中的静态成员变量的。
    __declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面。__declspec(dllexport)用于Windows中的动态库中,声明导出函数、类、对象等供外面调用,省略给出.def文件。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等
    .def文件(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件。.def文件或__declspec(dllexport)都是将公共符号导入到应用程序或从DLL导出函数。如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件。

    2019年5月1日11:00:19

    5. 标准的预处理器宏

    已遇/常用:
    * __cplusplus 使用 C++ 编译器编译
    * __DATE__ 编译时的日期
    * __FILE__ 编译文件名
    * __func__ 同 __FUNCTION__
    * __LINE__ 当前行号
    * __TIME__ 编译时系统时间
    参考:C++预处理_百度百科
    GNU编译器:gcc中的预编译宏

    6. 汇编

    参考:汇编指令_百度百科
    汇编指令速查
    一点一点学汇编
    一点一点学汇编2
    机器语言:0,1代码→→汇编语言:助记符→→高级语言:如C,C++,java

    7. 计算机硬件

    参考:计算机基础系列一:计算机硬件
    计算机硬件基础知识_图文
    中央处理器(CPU,Central Processing Unit)

    CPU+输入输出+主存储器(内存)构成了电子计算机的三大核心组件:
    CPU是人的大脑,负责控制全身和运算;内存(主存储器)是人的记忆,负责临时存储;硬盘是人的笔记本,负责永久存储;输入设备是耳朵或眼睛或嘴巴,负责接收外部的信息存入内存;输出设备是你的脸部(表情)或者屁股,负责经过处理后输出的结果
    …………
    RAM(Random Access Memory):也叫主存,内存条,计算机内存性能主要取决于它。特点是其中存放的内容可随时供CPU读写,但断电后,存放的内容就会全部丢失。
    ROM(Read-Only Memory):一种只能读出不能写入的存储器断电后其中的内容不会丢失。通常用于存放固定的、执行特殊任务的程序。目前常用的是可擦除、可编程的只读存储器。
    …………
    参考:寄存器与存储器物理区别
    速度:寄存器(register) > 内存 > 硬盘
    寄存器与存储器物理区别:
    寄存器存在于CPU中,速度很快,但是所占面积大,数目有限;
    存储器就是内存,速度稍慢,所占面积小,但数量很大;
    计算机做运算时,必须将数据读入寄存器才能运算。

    8. __asm _emit

    __asm__和__volatile 在Visual C++中使用内联汇编(_emit) emit指令分析

    2019年5月2日08:42:44

    9. #pragma

    参考:#pragma_百度百科
    格式一般为: #Pragma Para
    常用参数列表:
    #Pragma message("消息文本")
      当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
    #pragma once
      只要在头文件.h的最开始加入这条指令就能够保证头文件被编译一次。
    #pragma hdrstop
      表示预编译头文件到此为止,后面的头文件不进行预编译。类似于条件编译。
    #pragma warning( disable : 4000 40; once : 3000; error : 2000 )
      #pragma warning(disable:4000 40) // 不显示4507和34号警告信息
      #pragma warning(once:3000) // 4385号警告信息仅报告一次
      #pragma warning(error:2000) // 把164号警告信息作为一个错误。
    #pragma pack(n)
      改变C编译器的字节对齐方式。一般用于结构体
      内存对齐,程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的"对齐系数"。

      #pragma  pack 1           作用:调整结构体的边界对齐,让其以一个字节对齐;<使结构体按1字节方式对齐>,取消各个结构成员之间的填充字节
      #pragma  pack ()
      
      例如:
      1 #pragma pack(1)
      2
      3 struct sample
      4 {
      5 char a;
      6 double b;
      7 };
      8
      9 #pragma pack()
      注:若不用#pragma pack(1)#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节);若用#pragma pack(1),则sample1字节方式对齐sizeof(sample)==9.(无空字节),比较节省空间啦,有些场合还可使结构体更易于控制。

    #pragma comment
      将一个注释记录放入一个对象文件或可执行文件中。注释类型:compiler、exestr、lib、linker。
      经常用到的是#pragma comment(lib,"*.lib")这类的。#pragma comment(lib,"Ws2_32.lib")表示链接Ws2_32.lib这个库。 和在工程设置里写上链入Ws2_32.lib的效果一样,不过用这种方法,别人在使用你的代码的时候就不用再设置工程settings了

    10. 结构体 vs 类

    参考:结构体_百度百科
    结构体(struct):数据集合。类与结构体本质是类型,而不是数据,所以不存在于内存中,不能被直接操作,只有被实例化时,才会变得可操作。
    结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。
    struct tag {
       member-list
    } variable-list ;
    在一般情况下,tag、member-list、variable-list这3部分至少要出现2个。
    在C语言中,结构体不能包含函数。C++的结构体可以包含函数,这样,C++的结构体也具有类的功能,与class不同的是,结构体包含的函数默认为public,而不是private。
    …………
    类与结构体在C++中有三点区别。
    (1)class中默认的成员访问权限是private的,而struct中则是public的。
    (2)从class继承默认是private继承,而从struct继承默认是public继承。
    (3)C++的结构体声明不必有struct关键字,而C语言的结构体声明必须带有关键字(使用typedef别名定义除外)。
    …………

    定义一个类
    class类名
    {
    public:
      公有成员
    private:
      私有成员
    protected:
      保护成员
    };
    public/private/protected成员,彼此之间都可以访问。private表示私有,私有的意思就是除了class自己之外(不考虑友元的话),任何人都不可以直接使用,私有财产神圣不可侵犯嘛,即便是子女,朋友,都不可以使用。
    成员函数可以在类内实现,也可以在类外实现。内部实现的成员函数被默认为加上了inline;外部实现的成员函数必须加上域操作符,即"类名::成员函数"。
    构造函数和析构函数不能被显式地调用,只能由编译器自动调用。
    有的种类只是一种抽象概念,现实中并没有实际存在的对应物。比如:假设所有的动物都会叫,我们可以定义一个类——"动物",定义类中的一个成员函数——"叫",我们知道猫的叫声,也知道狗的叫声,然而"动物"是如何"叫"的?——我们根本无法实现它。所以,我们引入了抽象类的概念,抽象类是无法被实例化的,无法声明抽象类的对象
    C++中包含纯虚函数的类是抽象类;
    纯虚函数的作用:在基类中不能对虚函数给出有意义的实现(让类先具有一个操作名称,而没有操作内容),而把它声明为纯虚函数,它的实现留给该基类的派生类去做。
    纯虚函数:virtual ReturnType Function()= 0;
    多态性
    :同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。在C++中,可以用虚函数,抽象类实现多态。
    在C++中使用:冒号表示继承,如class A:public B;表示派生类A从基类B继承而来;
      class A:public B //基类以公有方式被继承;
      class A:private B //基类以私有方式被继承;
      class A:protected B //基类以受保护方式被继承;
    如果没有访问控制符则默认为私有private继承。
    不管基类以何种方式被继承,基类的私有成员,仍然保有其私有性,被派生的子类不能访问基类的私有成员
    C++类(Class)总结
    C++中的基类与派生类

    C++中的继承(1) 三种继承方式

    11. try…catch

    参考:c++ try catch 问题
    VC++:catch(…)方法能够捕获几乎所 有类型的异常对象。
    try
    {
      受保护语句;
      if(出现某种错误) throw 异常;
      //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
    }
    catch(…) //catch( int& value ) //catch( double value[] )
    {
      异常处理语句;
      //除非try里面执行代码发生了异常,否则这里的代码不会执行
    }
    程序执行的流程有两种:
    (1)没有异常:try→受保护语句→其他语句。
    (2)有异常:try→受保护语句→throw异常→catch→异常处理语句。

    12. 常见系统异常

    参考:C++中常见的异常
    C++中的异常处理
    MFC异常与C++标准异常
    异常处理(exception handling):内存分配不足、数组下标越界、运算溢出或除数为零、打开文件失败
    bad_alloc:请求分配内存失败, operator new 或者 operator new []
    bad_exception:函数异常,通常是函数运行错误,抛出的异常
    bad_typeid:类型异常,通常用typeid操作符,作用于一个NULL指针时,而该指针是带有虚函数的类,这时抛出bad_typeid异常
    bad_cast:转换异常,使用dynamic_cast转换引用失败的时候
    C++头文件:
    <exception>:定义了最通用的异常类,仅报告异常发生,不提供额外信息。
    <stdexcept>:定义了标准异常类
      exception    最常见的问题
      runtime_error    运行时错误:仅在运行时才能检测到的问题
      range_error    运行时错误:生成的结果超出了有意义的值域范围
      overflow_error    运行时错误:计算上溢
      underflow_error    运行时错误:计算下溢
      logic_error    逻辑错误:可在运行前检测到的问题
      domain_error    逻辑错误:域错误
      invalid_argument    逻辑错误:无效参数
      length_error    逻辑错误:试图生成一个超出该类型最大长度的对象
      out_of_range    逻辑错误:使用一个超出有效范围的值
    <new>:定义了bad_alloc异常类型
    <type_info>:定义了bad_cast异常类型

    13. IDE(集成开发环境,Integrated Development Environment )

    是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。

    14. MFC (微软基础类库,Microsoft Foundation Classes)

    参考:MFC_百度百科
    是微软公司提供的一个类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。

    描述

    Windows句柄

    windows句柄

    MFC Object

    窗口

    HWND

    hwnd

    CWnd and CWnd-derived classes

    设备上下文

    HDC

    hdc

    CDC and CDC-derived classes

    菜单

    HMENU

    hmenu

    CMenu

    HPEN

    hpen

    CGdiObject类,CPen和CPen-derived classes

    刷子

    HBRUSH

    hbrush

    CGdiObject类,CBrush和CBrush-derived classes

    字体

    HFONT

    hfont

    CGdiObject类,CFont和CFont-derived classes

    位图

    HBITMAP

    hbitmap

    CGdiObject类,CBitmap和CBitmap-derived classes

    调色板

    HPALETTE

    hpalette

    CGdiObject类,CPalette和CPalette-derived classes

    区域

    HRGN

    hrgn

    CGdiObject类,CRgn和CRgn-derived classes

    图像列表

    HimageLIST

    himagelist

    CimageList和CimageList-derived classes

    套接字

    SOCKET

    socket

    CSocket,CAsynSocket及其派生类

    OBJECT分以下几类:
    Windows对象,
    设备上下文对象,
    GDI对象(bitmap,brush,font,palette,pen,rgn),
    菜单,
    图像列表,
    网络套接字接口。

    15. CTime(时间) CTimeSpan(时间间隔)

    MFC:CTime类和CTimeSpan类

    16. static_cast

    参考:static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较
    标准C++中有四个类型转换符(显式//强转之前加这4个类型转换符):
      static_cast <new_type> (expression) 静态转换
      dynamic_cast <new_type> (expression) 动态转换
      reinterpret_cast <new_type> (expression) 重解释转换
      const_cast <new_type> (expression)常量向非常量转换
    上行转换(up-casting):(父类 *)子类
    下行转换(down-casting):(子类 *)父类 不安全
    C风格转换是"万能的转换",但需要程序员把握转换的安全性,编译器无能为力;
    static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性;
    dynamic_cast要求转换类型必须是指针或引用,且在下行转换时要求基类是多态的(基类中包含至少一个虚函数),如果发现下行转换不安全,dynamic_cast返回一个null指针,dynamic_cast总是认为void*之间的转换是安全的;
    reinterpret_cast可以对无关类指针进行转换,甚至可以直接将整型值转成指针,这种转换是底层的,有较强的平台依赖性,可移植性差;
    const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。

    17. TRACE

    参考:TRACE、TRACE0、TRACE1、TRACE2、TRACE3
    TRACE()的用法总结
    在debug下,可利用TRACE,打印出某些变量,方便调试,类似printf。
    比如:
    MFC:TRACE( "The value of x is %d ", x );
    C++写法:
      #include <atltrace.h>
      #define TRACE ATLTRACE
      TRACE(L"%s/t%d/n", string, number);

    18. UpdateData(true);

    参考:UpdateData(TRUE)和UpdateData(FALSE)的区别

    VC++/MFC
    UpdateData(true); //用于将屏幕上控件中的数据交换到变量中,前提:为控件关联上变量才行。
    UpdateData(false); //用于将数据在屏幕中对应控件中显示出来,前提:为控件关联上变量才行。

    19. _T

    _T("")是一个宏,定义于tchar.h下。作用是让你的程序支持Unicode编码。
    不常用,可参考:绕死你不偿命的UNICODE、_UNICODE、__TEXT、__T、_T、_TEXT、TEXT宏

    20. 字符集ASCII与UNICODE

    参考:所谓编码--泛谈ASCII、Unicode、UTF8、UTF16、UCS-2等编码格式
    字符编码笔记:ASCII,Unicode 和 UTF-8
    ANSI单字节;
    UNICODE双字节;将世界上所有的符号都纳入其中,每一个符号都给予一个独一无二的编码;覆盖全面,但会造成存储浪费。由此产生UTF(UnicodeTransformationFormat的缩写,意为Unicode转换格式)。UTF-8是一种变长的编码方式;是Unicode 的实现方式之一。

    21. #error

    C/C++语言的预处理命令之一,当预处理器预处理到#error命令时将停止编译并输出用户自定义的错误消息。
    #error 用户自定义的错误消息。
    ---eg:
    #ifndef __cplusplus
    #error 亲,您当前使用的不是C++编译器噢!
    #endif
    #include <stdio.h>
    int main()
    {
      printf("Hello,World!");
      return 0;
    }

    #pragma  pack 1           作用:调整结构体的边界对齐,让其以一个字节对齐;<使结构体按1字节方式对齐>,取消各个结构成员之间的填充字节
    #pragma  pack
    ()

    例如:
    1 #pragma pack(1)
    2
    3 struct sample
    4 {
    5 char a;
    6 double b;
    7 };
    8
    9 #pragma pack()
    注:若不用#pragma pack(1)#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节);若用#pragma pack(1),则sample1字节方式对齐sizeof(sample)==9.(无空字节),比较节省空间啦,有些场合还可使结构体更易于控制。

  • 相关阅读:
    ANDROID BINDER机制浅析
    ANDROID权限机制
    运算符
    Give root password for maintenance
    安装python工具
    gitlab
    jumpserver
    python环境安装
    inode
    升级openssh漏洞
  • 原文地址:https://www.cnblogs.com/yeyeye123/p/10807945.html
Copyright © 2011-2022 走看看