笔记70-75

 

71.关于调用约定

   调用约定(Calling convention)决定了以下内容:
    1)
参数的压栈顺序(自右向左还是自左向右)
    2)
函数返回时,由调用函数还是被调用函数清理入栈的参数

    3)
编译时函数名的转换

一共有五种调用约定.

1.__stdcall

参数自右向左压栈

被调用函数在返回前清理入栈参数

C编译时函数名的转换:_function@number

其中function为函数名,number为参数的字节数

例:int MyFunc(int a, int b)

    _MyFucn@8

C++编译时函数名的转换:?function@@YG****@Z或者?function@@YG*XZ

若函数有参数,以@Z结束;若函数无参数,则以Z结束

其中function为函数名,*代表参数表,为下列值:

      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"代表一次重复

参数表第一项为返回类型,其后跟参数的类型,指针标识在其所指数据类型前

例:int MyFunc1(unsigned char *arg1, unsigned long arg2)

    ?MyFunc1@@YGHPAEK@Z

    void MyFunc2(char *arg1, char *arg2, char *arg3)

    ?MyFunc2@@YGXPAD00@Z

    void MyFunc3()

    ?MyFunc3@@YGXXZ

C++编译器转换函数名时更多的考虑了参数,主要是为了方便函数重载,而C语言则不存在函数重载问题

 

2.__cdecl

参数自右向左压栈

调用函数在函数返回后清理入栈参数

C编译时函数名的转换:_function

其中function为函数名

例:int MyFunc(int a, int b)

    _MyFucn

C++编译时函数名的转换:同__stdcall,把YG改为YA

注意:对于可变参数的成员函数,始终使用__cdecl的转换方式

 

3.__fastcall

使用ECX传递第一个参数,EDX传递第二个参数,其余参数自右向左压栈

被调用函数在返回前清理入栈参数

C编译时函数名的转换:@function@number

其中function为函数名,number为参数的字节数

例:int MyFunc(int a, int b)

    @MyFucn@8

C++编译时函数名的转换:同__stdcall,把YG改为YI

 

调用约定可以在Project->Setting...->C/C++->Code Generation中的Calling convention中进行设置,缺省状态为__cdecl

 

4.thiscall

thiscall不是一个关键字,因此不能在程序中明确指定,它是C++类成员函数缺省的调用约定。由于成员函数调用涉及到一个this指针,因此必须进行特殊处理。

参数自右向左压栈

如果参数个数确定,this指针通过ECX传递给被调用者;如果参数个数不定,this指针在所有参数压栈后被压入堆栈

如果参数个数确定,被调用函数自己清理堆栈;如果参数个数不定,由调用函数清理堆栈

可见,对于参数个数固定情况下,它类似于__stdcall,不定时则类似__cdecl

 

5.naked call

使用前四种调用约定时,在进入函数时编译器会产生代码来保存ESIEDIEBXEBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这样的代码。更特殊的是,不能用return返回返回值,只能用插入汇编返回结果。

naked call必须和__declspec连用,即__declspec(naked)naked call还可以和其他调用约定联用,如:

    __declspec(naked) int __stdcall function(int a, int b)

 

   使用场合

   1_beginthread需要__cdecl的线程函数地址,_beginthreadexCreateThread需要__stdcall的线程函数地址。

   2main函数必须是__cdecl,一般的WIN32函数和回调函数都是__stdcall,并且专门定义了宏来标识:

   #define CALLBACK __stdcall

   #define WINAPI  __stdcall

   3.如果某函数在C语言编译器中编译,而在C++文件使用,由于两种编译器对函数名的解析不一样,因此需要在C++文件中使用extern "C"进行声明,否则会发生链接错误:

#ifdef _cplusplus

extern "C"{

#endif

int func(int a, int b);

#ifdef _cplusplus

}

#endif

extern "C"的调用约定会使得编译后的导出函数的名称和原来函数的名字相同。但是,

extern "C"不能用于导出一个类的成员函数,只能用于导出全局函数。

72.怎样在使用标准调用约定_stdcall时,不改变导出函数的名字

   在工程目录下手动建立一个文件projectname.def  ,利用project->Add to project->Files把该文件添加到工程中,在文件中写入:

LIBRARY projectname

 

EXPORTS

Fun1

Fun2

73.全局变量,局部变量,静态全局变量,静态局部变量,静态函数

   在一个.cpp文件中定义的全局变量,在所有的cpp文件中都是可见的。其作用域是全局和全时间的。局部可以重新定义和全局变量同名的变量来屏蔽掉全局变量,局部变量的生存期是其所在的大括号。

   静态全局变量是在静态内存区域分配的空间,其作用域是全时间但仅仅在定义它的cpp文件中有效,在其他的源文件中是不可见的。静态全局变量的值一旦被修改,在其生存期内是不会改变的。静态局部变量也是在静态内存区域分配的内存空间,其作用域是全时间的但仅仅在其定义的函数中可见,其他函数和cpp文件中都不可见。

   静态函数,仅仅在本cpp文件中声明,定义和使用的函数应该定义为静态函数,防止其他cpp文件调用。其他普通函数应该在头文件中声明,在头文件对应的cpp文件中定义。使用时包含对应的头文件就可以了。

74.关于MakeFile

规则:target ... : prerequisites ...
            command
            ...
            ...

target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),即伪目标。prerequisites就是,要生成那个target所需要的文件或是目标。    command也就是make需要执行的命令。(任意的Shell命令)

工作方式:

    1make会在当前目录下找名字叫“Makefile”“makefile”的文件。

    2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。

    3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。

    4、如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)

5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。

依赖关系:即需要的头文件,或生成可执行文件所需要的所有.obj文件。需要的头文件就是在cpp的头部列出的所有的include""但这其中不包括编译器提供的库文件,只是依赖自己编写的.h文件。可执行文件的依赖的与头文件和与头文件对应的cpp文件生成的obj文件。

隐含规则:它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来

伪目标:

.PHONY: Clean

Clean:

      Shell command

      ..........

这样在终端中输入: make Clean

就可以执行Clean下的这段代码,一般用于清理obj临时文件,而且放在makefile文件的末尾。

还可以用于多个终极目标时,在第一行设这伪目标,伪目标的依赖文件就可以是多个要生成的可执行文件。

命令行属性

- :减号表示执行一条语句时如果发生错误,不终止而是继续执行。

+ :加号表示,只要本条规则的目标文件过期,始终执行该条command,不论在make     

        命令中如何设置选项。

@ :执行本条命令时不再屏幕上打印命令的内容。

上述三个属性可以进行任意的叠加。

注释:  注释采用#开始,一般注释放在最后或第一行,如果注释放在一条语句的后面时要紧跟在语句的后面,不能有空格,因为有时候空格会被理解为字符。如果要用到#字符以

/#来完成。

包含其他的makefile文件:

     Include  filename

不可以以tab开头,filename可以是含有路径的文件名称。Include不一定放在一个makefile的开始,而是在需要的位置进行包含,原理就是把包含的文件原封不动的展开在包含的位置上。

自定义命令

如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以“define”开始,以“endef”结束,如:

    define run-yacc
    yacc $(firstword $^)
    mv y.tab.c $@
    endef

这里,“run-yacc”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”“endef”中的两行就是命令序列。

使用条件语句控制编译:

ifeq ($(CC),gcc)
        $(CC) -o foo $(objects) $(libs_for_gcc)
else
        $(CC) -o foo $(objects) $(normal_libs)
endif
判断两个变量是不是相等,决定如何编译。

bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif

判断一个变量是否已经定义来决定如何编译。

搜索目录:Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

    VPATH = src:../headers

上面的的定义指定两个目录,“src”“../headers”make会按照这个顺序进行搜索。目录由冒号分隔。(当然,当前目录永远是最高优先搜索的地方)。VPATH 变量写在makefile文件的开始部分。

另一个设置文件搜索路径的方法是使用make“vpath”关键字(注意,它是全小写的),这不是变量,这是一个make的关键字,这和上面提到的那个VPATH变量很类似,但是它更为灵活。它可以指定不同的文件在不同的搜索目录中。

     vpath %.h ../headers

     vpath %.c  foo
     vpath %   blish

使用变量

     变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”“#”“=”或是空字符(空格、回车等)。变量是大小写敏感的,“foo”“Foo”“FOO”是三个不同的变量名。传统的Makefile的变量名是全大写的命名方式,推荐使用大小写搭配的变量名,如:MakeFlags。这样可以避免和系统的变量冲突,而发生意外的事情。

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号()或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。
    = 
:这种赋值的方法是把右边的一个字符串或者变量赋给左边,不管右边的变量是否定义,没有定义的话就当做字符串,在以后定义的话就做类似宏的替换。

:= :立即展开的变量,如果没有定义会被当做字符串,如果是没有定义的变量的引用$(a)就会被忽略。

= :这种赋值是,如果变量已经赋值,则没有动作。如果没有赋值,则进行赋值。

+=  :追加赋值,把一个字符串或者变量追加到一个变量的末尾并用空格分开。

还有一些系统预定义变量:包括

CC                cc

CXXFLAGS        g++

CFLAGS           -o

MAKE             make

SHELL         

PWD

AR                ar

ARFLAGS         -ruv

自动化变量

$@

    表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。

$%

    仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o""$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a]Windows下是[.lib]),那么,其值为空。

$<

    依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。

$?

    所有比目标新的依赖目标的集合。以空格分隔。

$^

    所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。

$+

    这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。

$* 

   如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。

75.C语言文件操作

   头文件:stdlib.h

  文件指针:FILE *fp;

  打开文件:fp = fopen("const char *filename", "MODEL");  返回文件指针或者NULL

            r ->只读文本文件;w->只写文本文件;a->向文本文件追加数据;

            rb ->只读二进制文件;wb->只写二进制文件;ab->向二进制文件追加数据;

            r+->先读后写一个文本文件;w+->先写后读一个文本文件;a+->向文本文件追

                                                                        加数据;

            rb+->先读后写一个二进制文件;wb+->先写后读一个二进制文件;ab+->向二

 

                                                              进制文件追加数据;

  关闭文件:        fclose(fp); 返回0,或者EOF

  写入一个字符:    char c = fputc (ch, fp);返回写入的字符或者EOF

  读出一个字符:    char c = fgetc (fp); 返回一个字符或者EOF

  判断文件是否结束:feof (fp); 返回1真,或者0假。

  写入一个数据:    fread (buffer, size, count, fp); 返回count或者0

                         Buffer,存放地址。Size,一个数据项的大小,count,多少个数据项。

  读出一个数据:    fwrite (buffer,size, count,fp); 返回count或者0.

  写入字符串:      fputs (str, fp); 返回0或者EOF

  读出字符串:      fgets (str,n,fp); 返回str地址或者EOF

                              只是读取n-1个最后添加一个'/0'

  立即写入:        fflush(fp);

  文件指针移动:    fseek(fp, offset, pos);

                              Pos= SEEK_SETSEEK_ENDSEEK_CUR

  获取文件指针:    ftell(fp); 返回文件指针的当前位置。

  获取错误号:      ferror(fp); 返回0或者错误号码。

  清除错误号码:    clearerr(fp);

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值