服务器升级中,可能出现不稳定的情况,尽请谅解!
★掌心万年历注册★
FiT工作室请访问:http://www.PDA01.com/
历史上的今天:http://www.PDA01.com/histoday/
★掌心万年历注册★
FiT工作室请访问:http://www.PDA01.com/
历史上的今天:http://www.PDA01.com/histoday/
![]() |
[置顶] Job Hunting -- 1.起因 |
![]() |
[
2005/11/09 23:16 | by turbozv ]
2005/11/09 23:16 | by turbozv ]
[
2006/11/13 17:33 | by turbozv ]
2006/11/13 17:33 | by turbozv ]
根据ISO/IEC 14882:2003(E)对C++的标准定义来看,第15页到19页,一个integer后缀可以为:
uU, fF, lL
不过,微软扩展了一些后缀:
http://msdn2.microsoft.com/en-us/library/00a1awxf.aspx
iN (N=8, 16, 32, 64), LL, ll
比如:-1i16, 256i32等等……
让人疑惑的是这个iN。
对于iN的修饰的整型长度为N位,比如sizeof(0i8), sizeof(0i16), sizeof(0i32), sizeof(0i64) 的值分别为1, 2, 4, 8。
你可以将i8理解为(char), 所以 0i8 == (char)(0)。 (当然ui8就是unsigned char, 0ui8 == (unsigned char)0)
请看下面程序:
全部都是等价的操作。
那么,为什么微软要加这样一个定义呢?
来看看常用的地方:
我个人感觉就是避免了一个显式转换而已,其实也可以定义为:
HOHO~
再来看个例子:
要搞清楚这个问题就要知道运算符的优先顺序,"-"是修饰32768还是修饰32768i16的。试验的结果是后者。
所以 -32768i16 被编译器理解为 -(32768i16)。所以 a = -((short)(32768));
不过编译器不支持 (-32768)i16,因为()是表达式了,而i只能修饰定义的常量……
还有一个很让人疑惑的地方就是:
把编译开关设置为 /W4,结果是第一行没有产生警告信息,第二行有丢失数据的警告信息。 我想到的原因就是,常量赋值的时候,编译器很容易做结果检查,所以就自动帮程序员转换成正确的类型了。(你可以试试 char a = 128i32; 就会产生警告信息)。
结论:Compiler is smart enough!
uU, fF, lL
不过,微软扩展了一些后缀:
http://msdn2.microsoft.com/en-us/library/00a1awxf.aspx
iN (N=8, 16, 32, 64), LL, ll
比如:-1i16, 256i32等等……
让人疑惑的是这个iN。
对于iN的修饰的整型长度为N位,比如sizeof(0i8), sizeof(0i16), sizeof(0i32), sizeof(0i64) 的值分别为1, 2, 4, 8。
你可以将i8理解为(char), 所以 0i8 == (char)(0)。 (当然ui8就是unsigned char, 0ui8 == (unsigned char)0)
请看下面程序:
int a;
1)a = 256i8;
2)a = char(256);
3)char c = 256; a = c;
1)a = 256i8;
2)a = char(256);
3)char c = 256; a = c;
全部都是等价的操作。
那么,为什么微软要加这样一个定义呢?
来看看常用的地方:
#define _I32_MIN (-2147483647i32-1) /* minimum signed 32 bit value */
#define _I32_MAX 2147483647i32 /* maximum signed 32 bit value */
#define _UI32_MAX 0xffffffffui32 /* maximum unsigned 32 bit value */
#define _I32_MAX 2147483647i32 /* maximum signed 32 bit value */
#define _UI32_MAX 0xffffffffui32 /* maximum unsigned 32 bit value */
我个人感觉就是避免了一个显式转换而已,其实也可以定义为:
#define _I32_MIN (int32_t)(-2147483647-1) /* minimum signed 32 bit value */
#define _I32_MAX (int32_t)2147483647 /* maximum signed 32 bit value */
#define _UI32_MAX (uint32_t)0xffffffff /* maximum unsigned 32 bit value */
#define _I32_MAX (int32_t)2147483647 /* maximum signed 32 bit value */
#define _UI32_MAX (uint32_t)0xffffffff /* maximum unsigned 32 bit value */
HOHO~
再来看个例子:
int a = -32768i16;
问A等于多少?要搞清楚这个问题就要知道运算符的优先顺序,"-"是修饰32768还是修饰32768i16的。试验的结果是后者。
所以 -32768i16 被编译器理解为 -(32768i16)。所以 a = -((short)(32768));
不过编译器不支持 (-32768)i16,因为()是表达式了,而i只能修饰定义的常量……

还有一个很让人疑惑的地方就是:
char a = 1i32;
int a = 1; b = a;
int a = 1; b = a;
把编译开关设置为 /W4,结果是第一行没有产生警告信息,第二行有丢失数据的警告信息。 我想到的原因就是,常量赋值的时候,编译器很容易做结果检查,所以就自动帮程序员转换成正确的类型了。(你可以试试 char a = 128i32; 就会产生警告信息)。
结论:Compiler is smart enough!
[
2006/01/20 18:05 | by turbozv ]
2006/01/20 18:05 | by turbozv ]
编译器与解释器
作者:Cloud
大家可以通过 zhong335@gmail.com 跟他联系
为了让更多的人能够从本质上理解编译器和解释器的区别,我杜撰了一个小故事
来福与旺财的养牛场
来福和旺财有一个养牛场。本来养牛不是一件太难的事情,但是偏偏他俩养的牛都有特别的怪癖。奶牛阿圆只吃切成圆形的牧草,而奶牛阿方和阿三(印度来的?)分别只吃切成正方形和三角形的牧草。如果来福和旺财拿不和奶牛性格的草去喂食,阿X们不但不产奶而且还会鄙视来福和旺财。
于是来福和旺财分别有了自己的主意
来福的方案:
来福发明了三套大型碾碎机:圆圆碾碎机,方方碾碎机和三三碾碎机。每天收割了牧草,就分别放到这三套机器里碾碎给三头奶牛吃。但是一旦被碾碎了,这堆草就只能给某一头牛吃了。很明显阿方是不会吃给阿圆准备的草的。而且来福每天都要操作这三台机器,觉得比较麻烦。

旺财的方案:
旺财在考察了来福的方案后,发现每天操作三台机器真的很麻烦,而且有时有的牛吃不完,有的牛不够吃时,还不能在奶牛之间调配碾碎了的牧草。所以旺财有了不同的想法:口罩型碾碎机。
就像在图上看到的,旺财给每头奶牛装配了一台口罩碾碎机,所以三头牛完全可以在一个槽里吃草了,在吃之前口罩会自动把牧草碾碎成适合该牛食用的类型。旺财就轻松了,他每天只需要割割草就行了。
但是旺财被鄙视了???
是的,被来福鄙视了。来福观察后发现,旺财的口罩碾碎机的效率很低(因为比较小嘛)。阿圆食量大,吃来福的圆圆碾碎机的食物一个小时就饱了,但是戴着口罩吃的时候要吃十个小时!所以来福认为旺财的口罩碾碎机虽然省事,但只能喂喂小牛,完全不适合食量大的牛。
旺财也觉得这样做有问题,但他不想回到来福方案上,他改进了口罩方案:牧草预切割机。

呵呵,看到预切割做了什么吗?它把牧草割得小了一些,所以需要口罩碾碎机做的事情就少多了。(当然口罩碾碎机也要作适当改进适合预切割后的牧草,所以图上用蓝色表示)阿圆以前用口罩不是要吃十个小时吗,现在两三个小时就可以了。
编译器与解释器
好的,谢谢你有耐心看到这里,经过上面那个不太恰当的例子,相信你已经相当的糊涂了。那么我们试着回到技术方面来。
在上面的例子中
牧草 = 我们的各种编程语言,C/C++/C#, Java, Pascal, PHP, Python, Perl, Java Script等等
切割机 = 各种编译器
奶牛 = 各种CPU(不要告诉我Intel和AMD哦),比如x86,ARM,MIPS等等
那你应该知道了为什么奶牛会有吃不同形状牧草的嗜好了,这个奇怪的比喻是为了表示不同的CPU接受的不同的机器语言。
对应上面的奶牛图,编译器的图是这样的

源代码被编译成机器码,在CPU上运行。
而解释器是这样的

用解释器很方便,只需要直接“运行”就好了,不用像C那样有编译链接的工序。
为什么说这些语言是跨平台的?因为你写了程序以后,如果这个平台上有这种语言的解释器,只需要拿到这个平台上直接运行就可以了。你可以理解为:解释器是在“一边编译,一边运行”,它只是把以前程序员手工做的编译过程放在了运行程序的时候进行。
为什么我们一般说解释器的效率比较低?你也可以想象的是,一段程序在解释器中运行时可能会被编译多次,因为每次运行到这段程序时,都会重新编译一次,这样的开销是很大的。
所以诞生了Java,C#这样的预编译语言:

在运行之前,需要手动把源代码编译成中间代码(Java里叫字节码),然后在解释器中执行。
这种架构避免了上面纯解释器中编译源代码的开销,所以相对会有效率一些。
但是我不能骗你们,其实我画在纯解释器中的Python,Perl,PHP可能都不会是真的纯解释执行的,这样实在是太没有效率。Python在运行时会生成pyc的二进制临时文件,看起来很像是预编译的结果。只有JavaScript这种真的不会写得太长的语言(Ajax请原谅我)才会采用纯解释的运行方式。
作者:Cloud
大家可以通过 zhong335@gmail.com 跟他联系
为了让更多的人能够从本质上理解编译器和解释器的区别,我杜撰了一个小故事
来福与旺财的养牛场
来福和旺财有一个养牛场。本来养牛不是一件太难的事情,但是偏偏他俩养的牛都有特别的怪癖。奶牛阿圆只吃切成圆形的牧草,而奶牛阿方和阿三(印度来的?)分别只吃切成正方形和三角形的牧草。如果来福和旺财拿不和奶牛性格的草去喂食,阿X们不但不产奶而且还会鄙视来福和旺财。
于是来福和旺财分别有了自己的主意
来福的方案:
来福发明了三套大型碾碎机:圆圆碾碎机,方方碾碎机和三三碾碎机。每天收割了牧草,就分别放到这三套机器里碾碎给三头奶牛吃。但是一旦被碾碎了,这堆草就只能给某一头牛吃了。很明显阿方是不会吃给阿圆准备的草的。而且来福每天都要操作这三台机器,觉得比较麻烦。

旺财的方案:
旺财在考察了来福的方案后,发现每天操作三台机器真的很麻烦,而且有时有的牛吃不完,有的牛不够吃时,还不能在奶牛之间调配碾碎了的牧草。所以旺财有了不同的想法:口罩型碾碎机。
就像在图上看到的,旺财给每头奶牛装配了一台口罩碾碎机,所以三头牛完全可以在一个槽里吃草了,在吃之前口罩会自动把牧草碾碎成适合该牛食用的类型。旺财就轻松了,他每天只需要割割草就行了。
但是旺财被鄙视了???
是的,被来福鄙视了。来福观察后发现,旺财的口罩碾碎机的效率很低(因为比较小嘛)。阿圆食量大,吃来福的圆圆碾碎机的食物一个小时就饱了,但是戴着口罩吃的时候要吃十个小时!所以来福认为旺财的口罩碾碎机虽然省事,但只能喂喂小牛,完全不适合食量大的牛。
旺财也觉得这样做有问题,但他不想回到来福方案上,他改进了口罩方案:牧草预切割机。

呵呵,看到预切割做了什么吗?它把牧草割得小了一些,所以需要口罩碾碎机做的事情就少多了。(当然口罩碾碎机也要作适当改进适合预切割后的牧草,所以图上用蓝色表示)阿圆以前用口罩不是要吃十个小时吗,现在两三个小时就可以了。
编译器与解释器
好的,谢谢你有耐心看到这里,经过上面那个不太恰当的例子,相信你已经相当的糊涂了。那么我们试着回到技术方面来。
在上面的例子中
牧草 = 我们的各种编程语言,C/C++/C#, Java, Pascal, PHP, Python, Perl, Java Script等等
切割机 = 各种编译器
奶牛 = 各种CPU(不要告诉我Intel和AMD哦),比如x86,ARM,MIPS等等
那你应该知道了为什么奶牛会有吃不同形状牧草的嗜好了,这个奇怪的比喻是为了表示不同的CPU接受的不同的机器语言。
对应上面的奶牛图,编译器的图是这样的

源代码被编译成机器码,在CPU上运行。
而解释器是这样的

用解释器很方便,只需要直接“运行”就好了,不用像C那样有编译链接的工序。
为什么说这些语言是跨平台的?因为你写了程序以后,如果这个平台上有这种语言的解释器,只需要拿到这个平台上直接运行就可以了。你可以理解为:解释器是在“一边编译,一边运行”,它只是把以前程序员手工做的编译过程放在了运行程序的时候进行。
为什么我们一般说解释器的效率比较低?你也可以想象的是,一段程序在解释器中运行时可能会被编译多次,因为每次运行到这段程序时,都会重新编译一次,这样的开销是很大的。
所以诞生了Java,C#这样的预编译语言:

在运行之前,需要手动把源代码编译成中间代码(Java里叫字节码),然后在解释器中执行。
这种架构避免了上面纯解释器中编译源代码的开销,所以相对会有效率一些。
但是我不能骗你们,其实我画在纯解释器中的Python,Perl,PHP可能都不会是真的纯解释执行的,这样实在是太没有效率。Python在运行时会生成pyc的二进制临时文件,看起来很像是预编译的结果。只有JavaScript这种真的不会写得太长的语言(Ajax请原谅我)才会采用纯解释的运行方式。
[
2005/12/19 16:41 | by turbozv ]
2005/12/19 16:41 | by turbozv ]
图(Graph)是一种比树更复杂的数据结构。
让我们复习一下离散数学的知识,图 = 点集 + 边集,n个节点的图,边数最多C(n,2)。
一、图的存储(n个节点, e条边):
邻接矩阵
最常用的图静态存储办法,用一个n x n的数组存储任意两节点的连通情况(一般情况下同时存放权值),特点是创建,查找操作非常方便,查询两个节点是否连接的时间复杂度是O(1),不过空间开销很大S(n^2),求节点的入度出度为O(n)。
邻接表
S(n) = n + e
逆邻接表
十字链表(有向图)
邻接多重表(无向图)
让我们复习一下离散数学的知识,图 = 点集 + 边集,n个节点的图,边数最多C(n,2)。
一、图的存储(n个节点, e条边):
邻接矩阵
最常用的图静态存储办法,用一个n x n的数组存储任意两节点的连通情况(一般情况下同时存放权值),特点是创建,查找操作非常方便,查询两个节点是否连接的时间复杂度是O(1),不过空间开销很大S(n^2),求节点的入度出度为O(n)。
邻接表
S(n) = n + e
逆邻接表
十字链表(有向图)
邻接多重表(无向图)
[
2005/12/18 17:07 | by turbozv ]
2005/12/18 17:07 | by turbozv ]
[
2005/12/12 15:00 | by turbozv ]
2005/12/12 15:00 | by turbozv ]
1、《Data Structure》
点评:作为经典教材,CS的同学们都学过,不用过多介绍,我只想问一句:书中每个例程你能不看书10分钟以内完成么?如果不能,请仔细地再看一遍。
2、《The C Programming Language》

点评:丢掉谭老师的书吧,这本书才是入门C语言的Bible。记住:如果一开始开错了书,以后就错得太远了。如果你已经熟练C语言了,还是建议通读一遍,受益匪浅的。
3、《Expert C Programming》

点评:鱼书,C语言进阶读物,让你对C语言有更透彻的认识,C语言永远学不完的,never over to learn C.
4、《Programming Pearls》

点评:工程中遇到的问题的巧妙解法,不是算法专著,只是一本薄薄的小册子,当小说读最好:)
5、《The Prictice of Programming》

6、《Algorithms in C++》

7、《Data Structures and Algorithm Analysis in C》

8、《Computer Systems: A Programmer's Perspective》

点评:内容就和书名一样实际,以一个程序员的观点来看待计算机系统,比《组成原理》实际得多,对程序员来说是必须看的一本书。
9、《Compilers Principles,Techniques,and Tools》

点评:龙书
10、《Design Patterns Elements of Reusable Object-Oriented software》

点评:OO领域的绝对大作,工程领域中必用到的。
《Pattern-Oriented Software Architecture, Volume 1: A System of Patterns》

点评论:Jarod觉得这本书更实在
点评:作为经典教材,CS的同学们都学过,不用过多介绍,我只想问一句:书中每个例程你能不看书10分钟以内完成么?如果不能,请仔细地再看一遍。
2、《The C Programming Language》

点评:丢掉谭老师的书吧,这本书才是入门C语言的Bible。记住:如果一开始开错了书,以后就错得太远了。如果你已经熟练C语言了,还是建议通读一遍,受益匪浅的。
3、《Expert C Programming》

点评:鱼书,C语言进阶读物,让你对C语言有更透彻的认识,C语言永远学不完的,never over to learn C.
4、《Programming Pearls》

点评:工程中遇到的问题的巧妙解法,不是算法专著,只是一本薄薄的小册子,当小说读最好:)
5、《The Prictice of Programming》

6、《Algorithms in C++》

7、《Data Structures and Algorithm Analysis in C》

8、《Computer Systems: A Programmer's Perspective》

点评:内容就和书名一样实际,以一个程序员的观点来看待计算机系统,比《组成原理》实际得多,对程序员来说是必须看的一本书。
9、《Compilers Principles,Techniques,and Tools》

点评:龙书
10、《Design Patterns Elements of Reusable Object-Oriented software》

点评:OO领域的绝对大作,工程领域中必用到的。
《Pattern-Oriented Software Architecture, Volume 1: A System of Patterns》

点评论:Jarod觉得这本书更实在
[
2005/12/05 19:15 | by turbozv ]
2005/12/05 19:15 | by turbozv ]
感谢Knife撰写串,Knife是我教研室的同学,签华为成研所。
大家有任何问题可以联系他:knife028_AT_126_DOT_com
作者:Knife(knife028_AT_126_DOT_com)
有关串的定义和操作是大家在找工作时被问及较多的咚咚,在此和大家一起回顾和总结一下,达到共同学习的目的哈
一、串的基本概念
串(或字符串),是由零个或多个字符组成的有限序列。串中字符的数目称为串的长度。零个字符的串称为空串,它的长度为零。
串中任意个连续的字符组成的子序列称为该串的子串。包含子串的串相应地称为主串。通常称字符在序列中的序号称为该字符在串中的位置。子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。
串相等的充要条件:长度相等,且各个对应位置上的字符都相等。
空格串是指由一个或多个空格字符组成的串,其长度等于它包含的空格个数;空串是零个字符的串,其长度为零。
S1和S2为串,给出使S1||S2=S2||S1成立的所有可能条件如下:(||为连接符号)
1、S1和S2都为空串;
2、S1或S2其中之一为空串;
3、S1和S2为相同的串;
4、若两串长度不等,则长串由整数个短串组成。
串有三种机内表示方法
1、定长顺序存储表示;
2、堆分配存储表示;
3、块链存储表示。
随便提醒一下笔试者:C规定以字符'\0'作为字符串结束标志(考点哦)。
二、重要的串操作
以下函数中串采用定长顺序存储结构(类似于线性表的顺序存储结构),用一组地址连续的存储单元存储串值的字符序列.
#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN+1] //0号单元存放串长
串的实际长度可在这予定义长度的范围内随意,超过予定义长度的串值则被舍去
串长用下标为0的数组元素存储。
定位函数
串的置换操作
模式匹配的改进算法(KMP)
三、有关串的函数(C实现)
字符串逆序存储的递归算法
void InvertStore(char A[])
//字符串逆序存储的递归算法。
{ char ch;
static int i = 0;//需要使用静态变量
scanf ("%c",&ch);
if (ch!= '.') //规定'.'是字符串输入结束标志
{InvertStore(A);
A[i++] = ch;//字符串逆序存储
}
A[i] = ''; //字符串结尾标记
}//结束算法InvertStore。
long atoi(char X[])
//一数字字符串存于字符数组X中,本算法将其转换成数
{long num=0;
long htemp=1;
int j,i=1; //i 为数组下标
while (X[i]!= '') num=10*num+(X[i++]-'0');//当字符串未到尾,进行数的转换
if(X[0]=='-') return (-num); //返回负数
else
{ for (j=1;j htemp*=10;
return ((X[0]-'0')*htemp+num); //返回正数,第一位若不是负号,则是数字
}
}//算法atoi结束
实现字符串拷贝的函数 strcpy为:
void strcpy(char *s , char *t) /*copy t to s*/
{ while (*s++=*t++);
}
求两字符串中最大公共子串
// index存放子串在串s中的位置,length存放子串的长度
void maxcomstr(orderstring *s,*t; int index, length)
{int i,j,k,length1,con;
index=0;length=0;i=0;
while (i {j=0;
while(j { if (s[i]= =t[j])
{ k=1;length1=1;con=1;
while(con)
if (i+k<=s.len && j+k<=t.len && s[i+k]==t[j+k] ) { length1=length1+1;k=k+1; } else con=0;
if (length1>length) { index=i; length=length1; }
j+=k;
}
else j++;
}
i++;
}
}
大家有任何问题可以联系他:knife028_AT_126_DOT_com
作者:Knife(knife028_AT_126_DOT_com)
有关串的定义和操作是大家在找工作时被问及较多的咚咚,在此和大家一起回顾和总结一下,达到共同学习的目的哈
一、串的基本概念
串(或字符串),是由零个或多个字符组成的有限序列。串中字符的数目称为串的长度。零个字符的串称为空串,它的长度为零。
串中任意个连续的字符组成的子序列称为该串的子串。包含子串的串相应地称为主串。通常称字符在序列中的序号称为该字符在串中的位置。子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。
串相等的充要条件:长度相等,且各个对应位置上的字符都相等。
空格串是指由一个或多个空格字符组成的串,其长度等于它包含的空格个数;空串是零个字符的串,其长度为零。
S1和S2为串,给出使S1||S2=S2||S1成立的所有可能条件如下:(||为连接符号)
1、S1和S2都为空串;
2、S1或S2其中之一为空串;
3、S1和S2为相同的串;
4、若两串长度不等,则长串由整数个短串组成。
串有三种机内表示方法
1、定长顺序存储表示;
2、堆分配存储表示;
3、块链存储表示。
随便提醒一下笔试者:C规定以字符'\0'作为字符串结束标志(考点哦)。
二、重要的串操作
以下函数中串采用定长顺序存储结构(类似于线性表的顺序存储结构),用一组地址连续的存储单元存储串值的字符序列.
#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN+1] //0号单元存放串长
串的实际长度可在这予定义长度的范围内随意,超过予定义长度的串值则被舍去
串长用下标为0的数组元素存储。
定位函数
int Index(SString S, SString T, int pos)
{
//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0。
//其中,T非空,1<=pos<=Strlength(S).
int i, j;
i = pos;
j = 1;
while (i <= S[0] && j <= T[0]) {
if (S[i] == T[j]) {
++i;
++j;
} else {
i = i - j + 2;
j = 1;
}
}
if (j > T[0])
return i - T[0];
else
return 0;
}
{
//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0。
//其中,T非空,1<=pos<=Strlength(S).
int i, j;
i = pos;
j = 1;
while (i <= S[0] && j <= T[0]) {
if (S[i] == T[j]) {
++i;
++j;
} else {
i = i - j + 2;
j = 1;
}
}
if (j > T[0])
return i - T[0];
else
return 0;
}
串的置换操作
int Replace(SString & s1, SString s2, int i, int j)
{
//将s1中从位置i开始,长度为j的子串替换为s2
//替换成功则返回新的长度,否则返回-1
//其中,1<=i<=Strlength(s1).0<=j<=Strlength(s1).
int k;
if (i + j - 1 > s1[0])
return -1;
if (j > s2[0]) //被替换的串长度大于子串长度
for (k = i + j; k <= s1[0]; k++)
s1[k + s2[0] - j] = s1[k];
else if (j < s2[0]) //被替换的串长度小于子串长度
for (k = s1[0]; k >= i + j; k--)
s1[k + s2[0] - j] = s1[k];
for (k = 1; k <= s2[0]; k++)
s1[i + k - 1] = s2[k];
s1[0] = s1[0] - j + s2[0];
return s1[0];
}
{
//将s1中从位置i开始,长度为j的子串替换为s2
//替换成功则返回新的长度,否则返回-1
//其中,1<=i<=Strlength(s1).0<=j<=Strlength(s1).
int k;
if (i + j - 1 > s1[0])
return -1;
if (j > s2[0]) //被替换的串长度大于子串长度
for (k = i + j; k <= s1[0]; k++)
s1[k + s2[0] - j] = s1[k];
else if (j < s2[0]) //被替换的串长度小于子串长度
for (k = s1[0]; k >= i + j; k--)
s1[k + s2[0] - j] = s1[k];
for (k = 1; k <= s2[0]; k++)
s1[i + k - 1] = s2[k];
s1[0] = s1[0] - j + s2[0];
return s1[0];
}
模式匹配的改进算法(KMP)
三、有关串的函数(C实现)
字符串逆序存储的递归算法
void InvertStore(char A[])
//字符串逆序存储的递归算法。
{ char ch;
static int i = 0;//需要使用静态变量
scanf ("%c",&ch);
if (ch!= '.') //规定'.'是字符串输入结束标志
{InvertStore(A);
A[i++] = ch;//字符串逆序存储
}
A[i] = ''; //字符串结尾标记
}//结束算法InvertStore。
long atoi(char X[])
//一数字字符串存于字符数组X中,本算法将其转换成数
{long num=0;
long htemp=1;
int j,i=1; //i 为数组下标
while (X[i]!= '') num=10*num+(X[i++]-'0');//当字符串未到尾,进行数的转换
if(X[0]=='-') return (-num); //返回负数
else
{ for (j=1;j htemp*=10;
return ((X[0]-'0')*htemp+num); //返回正数,第一位若不是负号,则是数字
}
}//算法atoi结束
实现字符串拷贝的函数 strcpy为:
void strcpy(char *s , char *t) /*copy t to s*/
{ while (*s++=*t++);
}
求两字符串中最大公共子串
// index存放子串在串s中的位置,length存放子串的长度
void maxcomstr(orderstring *s,*t; int index, length)
{int i,j,k,length1,con;
index=0;length=0;i=0;
while (i
while(j
{ k=1;length1=1;con=1;
while(con)
if (i+k<=s.len && j+k<=t.len && s[i+k]==t[j+k] ) { length1=length1+1;k=k+1; } else con=0;
if (length1>length) { index=i; length=length1; }
j+=k;
}
else j++;
}
i++;
}
}
[
2005/12/04 00:26 | by turbozv ]
2005/12/04 00:26 | by turbozv ]
????? Yamir是我的师弟,也是我师弟Parvel的师弟,所以师弟关系具有传递性:P 他帮我完成了排序一章节,大家有任何问题可以联系他: http://www.sinklow.com/blog/
一、排序的概念
所谓排序,就是要让所有元素按递增或递减的顺序排列。
二、排序的分类
内部排序:只在主存中完成的排序(由于主存有限,所以内部排序的元素是有上限的)。
外部排序:利用磁盘等外存进行排序。
三、排序的稳定性
在待排序的元素中,存在多个相同的元素,经过排序后,这些元素的相对位置不变,该排序法就为稳定排序,否则为不稳定排序。
四、内部排序法
-----------------------------------------------------------
1.插入排序
算法思想
假设待排序的元素存放在数组A[N]中。初始时,A[0]自成1个有序区,无序区为A[1]~A[N-1]。从i=1起直至i=N-1为止,依次将A[i]插入当前的有序区A[0]~A[i-1]中。排序结束后为含N个元素的有序区。算法的平均时间复杂度为O(N^2)。
程序实现
void
InsertionSort( ElementType A[], int N )
{
??int j, P;
??
??ElementTyep Tmp;
??for( P = 1; P < N; P++ );
??{
????Tmp = A[ P ];
????for( j = p; j > 0 && A[ j - 1 ] > Tmp; j-- )
??????A[ j ] = A[ j - 1 ];
????A[ j ] = Tmp;
??}
}
--------------------------------------------------------InsertionSort( ElementType A[], int N )
{
??int j, P;
??
??ElementTyep Tmp;
??for( P = 1; P < N; P++ );
??{
????Tmp = A[ P ];
????for( j = p; j > 0 && A[ j - 1 ] > Tmp; j-- )
??????A[ j ] = A[ j - 1 ];
????A[ j ] = Tmp;
??}
}
2.希尔排序
算法思想
假设有N个待排序的元素,先取一个小于N的整数d1作为第一个增量,把所有距离为d1的倍数的元素放在同一个组中,在各组内进行插人排序;然后取第二个增量d2
程序实现
void
Shellsort( ElementType A[], int N )
{
??int i, j, Increment;
??ElementType Tmp;
??for( Increment = N / 2; Increment > 0; Increment /= 2 )
????for( i = Icrement; i < N; i++ )
????{
??????Tmp = A[ i ];
??????for( j = i; j >= Increment; j -= Increment )
????????if( Tmp < A[ j - Increment ] )
??????????A[ j ] = A[ j -Increment ];
????????else
??????????break;
??????A[ j ] = Tmp
????}
}
Shellsort( ElementType A[], int N )
{
??int i, j, Increment;
??ElementType Tmp;
??for( Increment = N / 2; Increment > 0; Increment /= 2 )
????for( i = Icrement; i < N; i++ )
????{
??????Tmp = A[ i ];
??????for( j = i; j >= Increment; j -= Increment )
????????if( Tmp < A[ j - Increment ] )
??????????A[ j ] = A[ j -Increment ];
????????else
??????????break;
??????A[ j ] = Tmp
????}
}
注:程序实现中采用的是希尔增量,采用不同的增量会影响到希尔排序的时间复杂度。效率比较高的增量有Sedgewick增量。
Sedgewick增量序列:9*4^i-9*2^i+1 或者 4^i-3*2^i+1
--------------------------------------------------------
3.堆排序
算法思想
将序列所存储的元素A[N]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的元素均不大于(或不小于)其左右孩子(若存在)结点的元素。算法的平均时间复杂度为O(NlogN)。
程序实现
#define LeftChild( i ) ( 2 * ( i ) + 1 )
void
PrecDown( ElementType A[ ], int i, int N )
{
??int Child;
??ElementType Tmp;
??for( Tmp = A[ i ]; LeftChild( i ) < N; i = Child )
??{
????Child = LeftChild( i );
????if( Child != N - 1 && A[ Child + 1 ] > A[ Child ] )
??????Child++;
????if( Tmp < A[ Child ] )
??????A[ i ] = A[ Child ];
????else
??????break;
??}
??A[ i ] = Tmp;
}
void
Heapsort( ElementType A[ ], int N )
{
??int i;
??
??for( i = N / 2; i >= 0; i-- )
????PrecDown( A, i, N )
??for( i = N - 1; i > 0; i-- )
??{
????Swap( &A[ 0 ], &A[ i ] );
????PercDown( A, 0, i )
??}
}
void
PrecDown( ElementType A[ ], int i, int N )
{
??int Child;
??ElementType Tmp;
??for( Tmp = A[ i ]; LeftChild( i ) < N; i = Child )
??{
????Child = LeftChild( i );
????if( Child != N - 1 && A[ Child + 1 ] > A[ Child ] )
??????Child++;
????if( Tmp < A[ Child ] )
??????A[ i ] = A[ Child ];
????else
??????break;
??}
??A[ i ] = Tmp;
}
void
Heapsort( ElementType A[ ], int N )
{
??int i;
??
??for( i = N / 2; i >= 0; i-- )
????PrecDown( A, i, N )
??for( i = N - 1; i > 0; i-- )
??{
????Swap( &A[ 0 ], &A[ i ] );
????PercDown( A, 0, i )
??}
}
--------------------------------------------------------------
4.直接选择排序
算法思想
每一趟从待排序的元素中选出最小的元素,顺序放在已排好序的子元素集的最后,直到全部元素排序完毕。算法的平均时间复杂度为O(N^2)。
程序实现
void
SelectSort( ElementType A[ ], int N )
{
??int i, j, k;
??ElementType Tmp;
??for( i = 0; i < N; i++ )
??{
????k = i;
????for( j = i+1; j <= N; j++ )
??????if( A[j] < A[k] )
????????k = j;
????if( k != i )
????{
??????Tmp = R[i];
??????R[i] = R[k];
??????R[k] = Tmp;
????}
??}
}
SelectSort( ElementType A[ ], int N )
{
??int i, j, k;
??ElementType Tmp;
??for( i = 0; i < N; i++ )
??{
????k = i;
????for( j = i+1; j <= N; j++ )
??????if( A[j] < A[k] )
????????k = j;
????if( k != i )
????{
??????Tmp = R[i];
??????R[i] = R[k];
??????R[k] = Tmp;
????}
??}
}
----------------------------------------------------------------
5.归并排序
算法思想
归并排序是将若干个已排序的表合并成一个有序的表。
程序实现(递归历程)
void
MSort( ElementType A[ ], ElementType TmpArray[ ], int Left, int Right )
{
??int Center;
??if( Left < Right )
??{
????Center = ( Left + Right ) / 2;
????MSort( A, TmpArray, Left, Center );
????MSort( A, TmpArray, Center + 1, Right );
????Merge( A, TmpArray, Left, Center + 1, Right );
??}
}
void
Mergesort( ElementType A[ ], int N )
{
??ElementType *TmpArray;
??TmpArray = malloc( N * sizeof( ElementType ) );
??if( TmpArray != NULL )
??{
????MSort( A, TmpArray, 0, N - 1 );
????free( TmpArray );
??}
??else
????FatalError( "No space for tmp array!!!" );
}
MSort( ElementType A[ ], ElementType TmpArray[ ], int Left, int Right )
{
??int Center;
??if( Left < Right )
??{
????Center = ( Left + Right ) / 2;
????MSort( A, TmpArray, Left, Center );
????MSort( A, TmpArray, Center + 1, Right );
????Merge( A, TmpArray, Left, Center + 1, Right );
??}
}
void
Mergesort( ElementType A[ ], int N )
{
??ElementType *TmpArray;
??TmpArray = malloc( N * sizeof( ElementType ) );
??if( TmpArray != NULL )
??{
????MSort( A, TmpArray, 0, N - 1 );
????free( TmpArray );
??}
??else
????FatalError( "No space for tmp array!!!" );
}
程序实现(Merge例程)
/* Lpos = start of left half, Rpos = start of right half */
void
Merge( ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd )
{
??int i, LeftEnd, NumElements, TmpPos;
??
??LeftEnd = Rpos - 1;
??TmpPos = Lpos;
??NumElements = RightEnd - Lpos + 1;
??/* main loop */
??while( Lpos <= LeftEnd && Rpos <= RightEnd )
????if( A[ Lpos ] <= A[ Rpos ] )
??????TmpArray[ TmpPos++ ] = A[ Lpos++ ];
????else
??????TmpArray[ TmpPos++ ] = A[ Rpos++ ];
??
??while( Lpos <= LeftEnd ) /* Copy rest of first half */
????TmpArray[ TmpPos++ ] = A[ Lpos++ ];
??while( Rpos <= RightEnd ) /* Copy rest of second half */
????TmpArray[ TmpPos++ ] = A[ Rpos++ ];
??/* Copy TmpArray back */
??for( i = 0; i < NumElements; i++, RightEnd-- )
????A[ RightEnd ] = TmpArray[ RightEnd ];
}
------------------------------------------------------------------void
Merge( ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd )
{
??int i, LeftEnd, NumElements, TmpPos;
??
??LeftEnd = Rpos - 1;
??TmpPos = Lpos;
??NumElements = RightEnd - Lpos + 1;
??/* main loop */
??while( Lpos <= LeftEnd && Rpos <= RightEnd )
????if( A[ Lpos ] <= A[ Rpos ] )
??????TmpArray[ TmpPos++ ] = A[ Lpos++ ];
????else
??????TmpArray[ TmpPos++ ] = A[ Rpos++ ];
??
??while( Lpos <= LeftEnd ) /* Copy rest of first half */
????TmpArray[ TmpPos++ ] = A[ Lpos++ ];
??while( Rpos <= RightEnd ) /* Copy rest of second half */
????TmpArray[ TmpPos++ ] = A[ Rpos++ ];
??/* Copy TmpArray back */
??for( i = 0; i < NumElements; i++, RightEnd-- )
????A[ RightEnd ] = TmpArray[ RightEnd ];
}
6.冒泡排序
算法思想
两两比较待排序的元素,发现两个元素的次序相反时即进行交换。算法的平均时间复杂度为O(N^2)。
程序实现
void
BubbleSort( ElementType A[], int N )
{
??int i, j;
??ElementType Tmp;
??
??for( i=0; i ??{
????for( j=N-1; j>i; j--)
??????if( A[j] < A[j-1] )
??????{
????????Tmp = A[j];
????????A[j] = A[j-1];
????????A[j] = Tmp;
??????}
??}
}
BubbleSort( ElementType A[], int N )
{
??int i, j;
??ElementType Tmp;
??
??for( i=0; i
????for( j=N-1; j>i; j--)
??????if( A[j] < A[j-1] )
??????{
????????Tmp = A[j];
????????A[j] = A[j-1];
????????A[j] = Tmp;
??????}
??}
}
------------------------------------------------------
7.快速排序
算法思想
快速排序是是一种分治的递归算法。分治法的基本思想是:将元素集分解为若干个子集合。递归地解这些子集合,然后将这些子集合问题的解组合为原元素集。快速排序算法被认为是理论上高度优化的一种排序算法。平均时间复杂度为O(NlogN)。
程序实现
/* Return median of Left, Center, and Right */
/* Order these and hide the pivot */
ElementType
Median3( ElementType A[ ], int Left, int Right )
{
??int Center = ( Left + Right ) / 2;
??if( A[ Left ] > A[ Center ] )
????Swap( &A[ Left ], &A[ Center ] );
??if( A[ Left ] > A[ Right ] )
????Swap( &A[ Left ], &A[ Right ] );
??if( A[ Center ] > A[ Right ] )
????Swap( &A[ Center ], &A[ Right ] );
??/* Invariant: A[ Left ] <= A[ Center ] <= A[ Right ] */
??Swap( &A[ Center ], &A[ Right - 1 ] );??/* Hide pivot */
??return A[ Right - 1 ];??/* Return pivot */
}
#define Cutoff ( 3 )
void
Qsort( ElementType A[ ], int Left, int Right )
{
??int i, j;
??ElementType Pivot;
??if( Left + Cutoff <= Right )
??{
????Pivot = Median3( A, Left, Right );
????i = Left; j = Right - 1;
????for( ; ; )
????{
??????while( A[ ++i ] < Pivot ){ }
??????while( A[ --j ] > Pivot ){ }
??????if( i < j )
????????Swap( &A[ i ], &A[ j ] );
??????else
????????break;
????}
????Swap( &A[ i ], &A[ Right - 1 ] );??/* Restore pivot */
????Qsort( A, Left, i - 1 );
????Qsort( A, i + 1, Right );
??}
??else??/* Do an insertion sort on the subarray */
????InsertionSort( A + Left, Right - Left + 1 );
}
void
Quicksort( ElementType A[ ], int N )
{
??Qsort( A, 0 , N-1 );
}
-----------------------------------------------------------------/* Order these and hide the pivot */
ElementType
Median3( ElementType A[ ], int Left, int Right )
{
??int Center = ( Left + Right ) / 2;
??if( A[ Left ] > A[ Center ] )
????Swap( &A[ Left ], &A[ Center ] );
??if( A[ Left ] > A[ Right ] )
????Swap( &A[ Left ], &A[ Right ] );
??if( A[ Center ] > A[ Right ] )
????Swap( &A[ Center ], &A[ Right ] );
??/* Invariant: A[ Left ] <= A[ Center ] <= A[ Right ] */
??Swap( &A[ Center ], &A[ Right - 1 ] );??/* Hide pivot */
??return A[ Right - 1 ];??/* Return pivot */
}
#define Cutoff ( 3 )
void
Qsort( ElementType A[ ], int Left, int Right )
{
??int i, j;
??ElementType Pivot;
??if( Left + Cutoff <= Right )
??{
????Pivot = Median3( A, Left, Right );
????i = Left; j = Right - 1;
????for( ; ; )
????{
??????while( A[ ++i ] < Pivot ){ }
??????while( A[ --j ] > Pivot ){ }
??????if( i < j )
????????Swap( &A[ i ], &A[ j ] );
??????else
????????break;
????}
????Swap( &A[ i ], &A[ Right - 1 ] );??/* Restore pivot */
????Qsort( A, Left, i - 1 );
????Qsort( A, i + 1, Right );
??}
??else??/* Do an insertion sort on the subarray */
????InsertionSort( A + Left, Right - Left + 1 );
}
void
Quicksort( ElementType A[ ], int N )
{
??Qsort( A, 0 , N-1 );
}
8.其他排序还有一些,诸如快速选择排序,桶式排序,基数排序等等。
---------------------------------------------------------------
五、外部排序法
基本的外部排序算法使用归并排序中的Merge例程。
六、排序算法的上下界证明
这个都是数学证明了,Job Hunting中应该不用写了^^。
<转载请注明出处,谢谢>
Reference:<>
[
2005/11/29 09:44 | by turbozv ]
2005/11/29 09:44 | by turbozv ]
感谢Faust撰写C函数调用,Faust是我教研室的同学,签南京中兴。
-------------------------------------------------------------------------------------------------
作者:Faust ( wsgfaust_AT_163_DOT_com )
C中采用了不同的调用方式来调用函数,这里的函数调用概念可能与我们通常所理解的函数调用有所不同,它们指的是处理器在处理函数上的差异。理解这些不同的方式有助于我们来调试程序和链接我们的代码。在此我想讨论一下主要的四种函数调用方法以及之间的区别,它们是__stdcall、__cdecl、__fastcall、thiscall。当然,还有一些更加不常用的函数调用方法比如naked call我也将顺便提及。
不同的函数调用方法之间的主要有以下一些区别:
① 当参数个数多于一个时,按照什么顺序把参数压入堆栈函数调用后
② 谁来恢复堆栈
③ 编译后的修饰名规则
__stdcall:将参数压栈是按PASCAL语言的顺序(从右到左),通常用于WINAPI中。它是由被调用者将参数从栈中清除的,所以它的编译文件比__cdecl小。__stdcall是Windows API函数中默认的调用约定,被调函数自己在退出时清空堆栈。这种调用方式不能实现变参函数,因为被调函数不能事先知道弹栈数量,但在主调函数中是可以做到的,因为参数数量由主调函数确定。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。如函数int func(int a, double b)的修饰名是_func@12。
编译选项/Gz。
注意:在创建DLL时,一般使用__stdcall调用(Win32 Api方式),采用__functionname@number命名规则,因而各种语言间的DLL能互相调用。也就是说,DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。
__cdecl:是C语言采用的默认调用方法,参数按从右到左的顺序压入栈,由调用者把参数弹出栈,它的优点是支持printf这样的可变参数调用。一般可变参数函数的调用都采用这种方式,比如int __cdecl scanf (const char *format,…)。对于"C",修饰名是在函数名前加下划线,如函数void test(void)的修饰名是__test。除非声明为 extern "C",否则 C++ 函数将使用不同的名称修饰方案。
编译选项/Gd。
注意:CC++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改。
__fastcall:__fastcall调用较快,它通过CPU内部寄存器传递参数。头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以“@”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。
编译选项/Gr,通常减少执行时间。
注意:在对用内联程序集语言编写的任意函数使用__fastcall 调用约定时,一定要小心。您对寄存器的使用可能与编译器对它们的使用发生冲突。Microsoft 不保证不同编译器版本之间的 __fastcall 调用约定的实现相同。例如,16 位编译器与 32 位编译器的实现就不同。因此当使用 __fastcall 命名约定时,请使用标准包含文件。否则将获取无法解析的外部引用。
thiscall: 函数体 this指针默认通过ECX传递,其它参数从右到左入栈。thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理。3
thiscall意味着:参数从右向左入栈,如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈。对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。
nakedcall:
这是一个很少见的调用约定,一般程序设计者建议不要使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回结果。这一般用于实模式驱动程序设计。
讲到自右至左我想到了一个关于求值顺序的问题,巧合(???)的是,在C中求值顺序也是从右至左(不知道和压栈顺序是怎样的关系?)。我找到一个小例子。
void main()
{
int i=8;
printf("%dn%dn%dn%dn",++i,--i,i++,i--);
}
如按照从右至左的顺序求值。运行结果应为:
8
7
7
8
如对printf语句中的++i,--i,i++,i--从左至右求值,结果应为:
9
8
8
9
应特别注意的是,无论是从左至右求值, 还是自右至左求值,其输出顺序都是不变的, 即输出顺序总是和实参表中实参的顺序相同。由于Turbo C现定是自右至左求值,所以结果为8,7,7,8。
转载请注明出处,谢谢!
-------------------------------------------------------------------------------------------------
作者:Faust ( wsgfaust_AT_163_DOT_com )
C中采用了不同的调用方式来调用函数,这里的函数调用概念可能与我们通常所理解的函数调用有所不同,它们指的是处理器在处理函数上的差异。理解这些不同的方式有助于我们来调试程序和链接我们的代码。在此我想讨论一下主要的四种函数调用方法以及之间的区别,它们是__stdcall、__cdecl、__fastcall、thiscall。当然,还有一些更加不常用的函数调用方法比如naked call我也将顺便提及。
不同的函数调用方法之间的主要有以下一些区别:
① 当参数个数多于一个时,按照什么顺序把参数压入堆栈函数调用后
② 谁来恢复堆栈
③ 编译后的修饰名规则
__stdcall:将参数压栈是按PASCAL语言的顺序(从右到左),通常用于WINAPI中。它是由被调用者将参数从栈中清除的,所以它的编译文件比__cdecl小。__stdcall是Windows API函数中默认的调用约定,被调函数自己在退出时清空堆栈。这种调用方式不能实现变参函数,因为被调函数不能事先知道弹栈数量,但在主调函数中是可以做到的,因为参数数量由主调函数确定。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。如函数int func(int a, double b)的修饰名是_func@12。
编译选项/Gz。
注意:在创建DLL时,一般使用__stdcall调用(Win32 Api方式),采用__functionname@number命名规则,因而各种语言间的DLL能互相调用。也就是说,DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。
__cdecl:是C语言采用的默认调用方法,参数按从右到左的顺序压入栈,由调用者把参数弹出栈,它的优点是支持printf这样的可变参数调用。一般可变参数函数的调用都采用这种方式,比如int __cdecl scanf (const char *format,…)。对于"C",修饰名是在函数名前加下划线,如函数void test(void)的修饰名是__test。除非声明为 extern "C",否则 C++ 函数将使用不同的名称修饰方案。
编译选项/Gd。
注意:CC++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改。
__fastcall:__fastcall调用较快,它通过CPU内部寄存器传递参数。头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以“@”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。
编译选项/Gr,通常减少执行时间。
注意:在对用内联程序集语言编写的任意函数使用__fastcall 调用约定时,一定要小心。您对寄存器的使用可能与编译器对它们的使用发生冲突。Microsoft 不保证不同编译器版本之间的 __fastcall 调用约定的实现相同。例如,16 位编译器与 32 位编译器的实现就不同。因此当使用 __fastcall 命名约定时,请使用标准包含文件。否则将获取无法解析的外部引用。
thiscall: 函数体 this指针默认通过ECX传递,其它参数从右到左入栈。thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理。3
thiscall意味着:参数从右向左入栈,如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈。对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。
nakedcall:
这是一个很少见的调用约定,一般程序设计者建议不要使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回结果。这一般用于实模式驱动程序设计。
讲到自右至左我想到了一个关于求值顺序的问题,巧合(???)的是,在C中求值顺序也是从右至左(不知道和压栈顺序是怎样的关系?)。我找到一个小例子。
void main()
{
int i=8;
printf("%dn%dn%dn%dn",++i,--i,i++,i--);
}
如按照从右至左的顺序求值。运行结果应为:
8
7
7
8
如对printf语句中的++i,--i,i++,i--从左至右求值,结果应为:
9
8
8
9
应特别注意的是,无论是从左至右求值, 还是自右至左求值,其输出顺序都是不变的, 即输出顺序总是和实参表中实参的顺序相同。由于Turbo C现定是自右至左求值,所以结果为8,7,7,8。
转载请注明出处,谢谢!













