zoukankan      html  css  js  c++  java
  • C语言知识点

    __declspec(naked) 裸函数添加后编译器不对函数进行编译

    调用约定

    __cdecl  从右至左入栈  调用者清理栈

    __stdcall 从右至左入栈 自身清理堆栈

    __fastcall ECX/EDX传送前两个 剩下:从右至左入栈  自身清理堆栈

    C语言中的数据类型:

    基本类型 分为 整数类型和浮点类型

    构造类型 分为 数组类型、结构体类型、共用体(联合)类型

    指针类型

    空类型(void)

    学习数据类型的三个要素:

    1、存储数据的宽度

    2、存储数据的格式

    3、作用范围(作用域)

    数组和多维数组编译器的计算方式

    int arr[10][10][10] = {0};

    取arr[9][6][7]编译器的计算方式为9*10*10+6*10+7.

    取arr[4][6][5]编译器的计算方式为4*10*10+6*10+5

    int arr[10][3] = {0};

    取arr[3][2]编译器计算方式为 3*3 + 2

    指针

    一种带*号的数据类型,特征为:

    1. 宽度为4

    2. 可以做 ++ 或 --操作

    3. 可以和整数做相加和相减操作

    4. 可以和另一个同类型的指针做相减操作

    5. 可以做比较操作

    & 取地址操作对应的汇编指令为lea 取地址操作会在原来的数据类型前加1个*

    * 取值操作只可以对带*号的类型进行取值,取地址后数据类型减一个*

    结构体指针

    struct Student

    {

      int a;

      int b;

    };

    Student* student;

    结构体指针取值使用->符号

    student->a;

    student->b;

    数组指针:

    定义方式  int (*px)[5]; 

    取值操作需要使用2次*操作  *(*(px))也可以使用[]取值和*操作时一致的px[0][0]

    以此类推int (*px)[5][3];

    取值需要3次*操作

    *(*(*(px+1)+2)+3)  =  1*5*3*4 + 2*3*4 + 3*4 + 4 

    函数指针

    定义方式 int (*fun)(int,int);

    特征 占用4个字符  可以做比较操作  因为目标i的宽度补确定所以无法做其他的运算操作

    位运算

    &与运算  2&3   结果为2 2个位都为1结果才是1

    0000 0010

    0000 0011

    ---------------

    0000 0010

    |或运算  2|3 结果为3 2个位有一个位是1结果就是1

    0000 0010

    0000 0011

    ---------------

    0000 0011

    ~非运算  ~2 结果位FD 0的运算结果为1 1的运算结果为0

    0000 0010

    ---------------

    1111 1101

    ^异或运算 2^3 结果为1 2个位运算都为0的结果为0 都为1的结果为0 0和1的运算结果为1

    0000 0010

    0000 0011

    -----------------

    0000 0001

    << 左位移指令对应的汇编指令为SHL

    >> 右位移指令有符号数的汇编指令为SAR 无符号数的汇编指令为SHR

    一些常见的C语言操作

    #define  宏定义  分为无参数宏定义和有参数的宏定义

    无参数宏定义

    # define TRUE 1

    # define FALSE 0

    # define PI 3.1415926

    # define DEBUG 1

    注意事项

    1、只作字符序列的替换工作,不作任何语法的检查

    2、如果宏定义不当,错误要到预处理之后的编译阶段才能发现

    有参数的宏定义

    # define MAX(A,B) ((A) > (B)?(A):(B))

    代码 x= MAX( p, q)将被替换成 y=((p) >(q)?(p):(q)

    注意事项:

    1、宏名标识符与左圆括号之间不允许有空白符,应紧接在一起.

    2、宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换.

    3、为了避免出错,宏定义中给形参加上括号.

    4、末尾不需要分号.

    5、define可以替代多行的代码,记得后面加

    #define MALLOC(n,type)

    ((type*)malloc((n)*sizeof(type)))

    重复包含的解决办法(不是绝对的)

    malloc申请内存的使用方式:

    int* ptr;//声明指针

    //在堆中申请内存,分配128个int

    ptr = (int *)malloc(sizeof(int)*128);

    //无论申请的空间大小 一定要进行校验 判断是否申请成功

    if(ptr == NULL)

    {

      return 0;

    }

    //初始化分配的内存空间

    memset(ptr,0,sizeof(int)*128);

    //使用。。。

    *(ptr) = 1;

    //使用完毕 释放申请的堆空间

    free(ptr);

    //将指针设置为NULL

    ptr = NULL;

    注意事项:

    1、使用sizeof(类型)*n 来定义申请内存的大小

    2、malloc返回类型为void*类型 需要强制转换

    3、无论申请的内存有多小 一定要判断是否申请成功

    4、申请完空间后要记得初始化.

    5、使用完一定要释放申请的空间.

    6、将指针的值设置为NULL.

    静态链接库和动态链接库

    创建静态链接库:


    1、在VC6中创建项目:Win32 Static Library


    2、在项目中创建两个文件:xxx.h 和 xxx.cpp


    xxx.h文件:


    #if !defined(AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_)
    #define AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000


    int Plus(int x, int y);
    int Sub(int x, int y);
    int Mul(int x, int y);
    int Div(int x, int y);

    #endif


    xxx.cpp文件:


    int Plus(int x, int y)
    {
    return x+y;
    }
    int Sub(int x, int y)
    {
    return x-y;
    }
    int Mul(int x, int y)
    {
    return x*y;
    }
    int Div(int x, int y)
    {
    return x/y;
    }


    3、编译



    二、使用静态链接库:

    方式一:
    将xxx.h 和 xxx.lib复制到要使用的项目中

    在需要使用的文件中包含:#include "xxx.h"

    在需要使用的文件中包含:#pragma comment(lib, "xxx.lib")



    方式二:

    将xxx.h 和 xxx.lib复制到要使用的项目中

    在需要使用的文件中包含:#include "xxx.h"

    静态链接库的缺点:

    使用静态链接生成的可执行文件体积较大,造成浪费

    我们常用的printf、memcpy、strcpy等就来自这种静态库

    一、创建DLL


    1、源文件中: 2、头文件中


    int __stdcall Plus(int x,int y) extern "C" _declspec(dllexport) __stdcall int Plus (int x,int y);
    { extern "C" _declspec(dllexport) __stdcall int Sub (int x,int y);
    return x+y; extern "C" _declspec(dllexport) __stdcall int Mul (int x,int y);
    } extern "C" _declspec(dllexport) __stdcall int Div (int x,int y);
    int __stdcall Sub(int x,int y)
    {
    return x-y;
    }
    int __stdcall Mul(int x,int y)
    {
    return x*y;
    }
    int __stdcall Div(int x,int y)
    {
    return x/y;
    }


    说明:

    1、extern 表示这是个全局函数,可以供各个其他的函数调用;

    2、"C" 按照C语言的方式进行编译、链接

    __declspec(dllexport)告诉编译器此函数为导出函数;



    二、使用DLL

    方式一:隐式连接

    步骤1:将 *.dll *.lib 放到工程目录下面

    步骤2:将 #pragma comment(lib,"DLL名.lib") 添加到调用文件中

    步骤3:加入函数的声明

    extern "C" __declspec(dllimport) __stdcall int Plus (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Sub (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Mul (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Div (int x,int y);

    说明:

    __declspec(dllimport)告诉编译器此函数为导入函数;


    方式二:显示链接

    步骤1: //定义函数指针
    typedef int (__stdcall *lpPlus)(int,int);
    typedef int (__stdcall *lpSub)(int,int);
    typedef int (__stdcall *lpMul)(int,int);
    typedef int (__stdcall *lpDiv)(int,int);

    步骤2: //声明函数指针变量
    lpPlus myPlus;
    lpSub mySub;
    lpMul myMul;
    lpDiv myDiv;

    步骤3: // //动态加载dll到内存中
    HINSTANCE hModule = LoadLibrary("DllDemo.dll");

    步骤4: //获取函数地址
    myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
    mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
    myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
    myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");


    步骤5: //调用函数
    int a = myPlus(10,2);
    int b = mySub(10,2);
    int c = myMul(10,2);
    int d = myDiv(10,2);


    特别说明:

    Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。

    HMODULE 是代表应用程序载入的模块

    HINSTANCE 在win32下与HMODULE是相同的东西 Win16 遗留

    HWND 是窗口句柄

    其实就是一个无符号整型,Windows之所以这样设计有2个目的:

    1、可读性更好

    2、避免在无意中进行运算

    使用序号导出函数隐藏函数名

    1、*.h文件

    int Plus (int x,int y);
    int Sub (int x,int y);
    int Mul (int x,int y);
    int Div (int x,int y);


    2、*.cpp文件

    int Plus(int x,int y)
    {
    return x+y;
    }
    int Sub(int x,int y)
    {
    return x-y;
    }
    int Mul(int x,int y)
    {
    return x*y;
    }
    int Div(int x,int y)
    {
    return x/y;
    }


    3、*.def文件

    EXPORTS

    Plus @12
    Sub @15 NONAME
    Mul @13
    Div @16


    4、使用序号导出的好处:

    名字是一段程序就精华的注释,通过名字可以直接猜测到函数的功能

    通过使用序号,可以达到隐藏的目的.

  • 相关阅读:
    C# CodeFirst(EF框架)代码优先创建数据库
    Entity Framework 配置关系(1对1,1对0)
    Entity Framework 配置关系(1对1,1对0)
    EFDbContext的使用
    EFDbContext的使用
    编程模式·观察者模式、事件通知、消息队列三者区别
    编程模式·观察者模式、事件通知、消息队列三者区别
    设计模式发布订阅方式实现异步并发
    设计模式发布订阅方式实现异步并发
    关于访问asp.net网站时登录后的奇怪问题
  • 原文地址:https://www.cnblogs.com/louzi/p/10927673.html
Copyright © 2011-2022 走看看