函数指针优化(Debug编译通过,Release编译报错,为什么)
本文目录
- Debug编译通过,Release编译报错,为什么
- C语言中,函数和函数指针,效率上差很多吗
- 用指针优化学生排名(在函数中,用指针实现数据的输入输出以及数组的排序)
- C#和java比有什么优势
- 如何优化你的C代码
- std::vector中放函数指针,可以用std::find来查找吗
- 最近写程序是用到指针,我本来想再一个函数中定义静态指针,以为可以向静态变量一样在每次进入程序时指针
- 请问C语言高手:指向函数的指针(*p)(),p的值能不能用scanf输入呢为什么不行前面用int和char有区别吗
Debug编译通过,Release编译报错,为什么
对照这些选项看看 Release 版错误是怎样产生的 1. Runtime Library:链接哪种运行时刻函数库通常只对程序的性能产生影响。调试版本的 Runtime Library 包含了调试信息,并采用了一些保护机制以帮助发现错误,因此性能不如发布版本。编译器提供的 Runtime Library 通常很稳定,不会造成 Release 版错误;倒是由于 Debug 的 Runtime Library 加强了对错误的检测,如堆内存分配,有时会出现 Debug 有错但 Release 正常的现象。应当指出的是,如果 Debug 有错,即使 Release 正常,程序肯定是有 Bug 的,只不过可能是 Release 版的某次运行没有表现出来而已。 2. 优化:这是造成错误的主要原因,因为关闭优化时源程序基本上是直接翻译的,而打开优化后编译器会作出一系列假设。这类错误主要有以下几种: (1) 帧指针(Frame Pointer)省略(简称 FPO ):在函数调用过程中,所有调用信息(返回地址、参数)以及自动变量都是放在栈中的。若函数的声明与实现不同(参数、返回值、调用方式),就会产生错误 ————但 Debug 方式下,栈的访问通过 EBP 寄存器保存的地址实现,如果没有发生数组越界之类的错误(或是越界“不多”),函数通常能正常执行;Release 方式下,优化会省略 EBP 栈基址指针,这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。C++ 的强类型特性能检查出大多数这样的错误,但如果用了强制类型转换,就不行了。你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略,以确定是否此类错误。此类错误通常有: ● MFC 消息响应函数书写错误。正确的应为 afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); ON_MESSAGE 宏包含强制类型转换。防止这种错误的方法之一是重定义 ON_MESSAGE 宏,把下列代码加到 stdafx.h 中(在#include "afxwin.h"之后),函数原形错误时编译会报错 #undef ON_MESSAGE #define ON_MESSAGE(message, memberFxn) \ { message, 0, 0, 0, AfxSig_lwl, \ (AFX_PMSG)(AFX_PMSGW)(static_cast《 LRESULT (AFX_MSG_CALL \ CWnd::*)(WPARAM, LPARAM) 》 (&memberFxn) }, (2) volatile 型变量:volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统、其他进程和线程)。优化程序为了使程序性能提高,常把一些变量放在寄存器中(类似于 register 关键字),而其他进程只能对该变量所在的内存进行修改,而寄存器中的值没变。如果你的程序是多线程的,或者你发现某个变量的值与预期的不符而你确信已正确 的设置了,则很可能遇到这样的问题。这种错误有时会表现为程序在最快优化出错而最小优化正常。把你认为可疑的变量加上 volatile 试试。 (3) 变量优化:优化程序会根据变量的使用情况优化变量。例如,函数中有一个未被使用的变量,在 Debug 版中它有可能掩盖一个数组越界,而在 Release 版中,这个变量很可能被优化调,此时数组越界会破坏栈中有用的数据。当然,实际的情况会比这复杂得多。与此有关的错误有: ● 非法访问,包括数组越界、指针错误等。例如 void fn(void) { int i; i = 1; int a; { int j; j = 1; } a = 1;//当然错误不会这么明显,例如下标是变量 a = 1; } j 虽然在数组越界时已出了作用域,但其空间并未收回,因而 i 和 j 就会掩盖越界。而 Release 版由于 i、j 并未其很大作用可能会被优化掉,从而使栈被破坏。 3. _DEBUG 与 NDEBUG :当定义了 _DEBUG 时,assert() 函数会被编译,而 NDEBUG 时不被编译。除此之外,VC++中还有一系列断言宏。这包括: ANSI C 断言 void assert(int expression ); C Runtime Lib 断言 _ASSERT( booleanExpression ); _ASSERTE( booleanExpression ); MFC 断言 ASSERT( booleanExpression ); VERIFY( booleanExpression ); ASSERT_VALID( pObject ); ASSERT_KINDOF( classname, pobject ); ATL 断言 ATLASSERT( booleanExpression ); 此外,TRACE() 宏的编译也受 _DEBUG 控制。 所有这些断言都只在 Debug版中才被编译,而在 Release 版中被忽略。唯一的例外是 VERIFY() 。事实上,这些宏都是调用了 assert() 函数,只不过附加了一些与库有关的调试代码。如果你在这些宏中加入了任何程序代码,而不只是布尔表达式(例如赋值、能改变变量值的函数调用 等),那么 Release 版都不会执行这些操作,从而造成错误。初学者很容易犯这类错误,查找的方法也很简单,因为这些宏都已在上面列出,只要利用 VC++ 的 Find in Files 功能在工程所有文件中找到用这些宏的地方再一一检查即可。另外,有些高手可能还会加入 #ifdef _DEBUG 之类的条件编译,也要注意一下。 顺便值得一提的是 VERIFY() 宏,这个宏允许你将程序代码放在布尔表达式里。这个宏通常用来检查 Windows API 的返回值。有些人可能为这个原因而滥用 VERIFY() ,事实上这是危险的,因为 VERIFY() 违反了断言的思想,不能使程序代码和调试代码完全分离,最终可能会带来很多麻烦。因此,专家们建议尽量少用这个宏。 4. /GZ 选项:这个选项会做以下这些事 (1) 初始化内存和变量。包括用 0xCC 初始化所有自动变量,0xCD ( Cleared Data ) 初始化堆中分配的内存(即动态分配的内存,例如 new ),0xDD ( Dead Data ) 填充已被释放的堆内存(例如 delete ),0xFD( deFencde Data ) 初始化受保护的内存(debug 版在动态分配内存的前后加入保护内存以防止越界访问),其中括号中的词是微软建议的助记词。这样做的好处是这些值都很大,作为指针是不可能的(而且 32 位系统中指针很少是奇数值,在有些系统中奇数的指针会产生运行时错误),作为数值也很少遇到,而且这些值也很容易辨认,因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误。要特别注意的是,很多人认为编译器会用 0 来初始化变量,这是错误的(而且这样很不利于查找错误)。 (2) 通过函数指针调用函数时,会通过检查栈指针验证函数调用的匹配性。(防止原形不匹配) (3) 函数返回前检查栈指针,确认未被修改。(防止越界访问和原形不匹配,与第二项合在一起可大致模拟帧指针省略 FPO ) 通常 /GZ 选项会造成 Debug 版出错而 Release 版正常的现象,因为 Release 版中未初始化的变量是随机的,这有可能使指针指向一个有效地址而掩盖了非法访问。 除此之外,/Gm /GF 等选项造成错误的情况比较少,而且他们的效果显而易见,比较容易发现。 -------------------------------------------------------------- Release是发行版本,比Debug版本有一些优化,文件比Debug文件小 Debug是调试版本,包括的程序信息更多 Release方法: build-》batch build-》build就OK.
C语言中,函数和函数指针,效率上差很多吗
1.直接调用函数,编译的时候,被调函数的地址(或偏移)直接写入指令;2.使用函数指针时,运行期从内存中取地址,在使用call指令理论上,这存在效率差异。根据你的系统环境:服务器、PC还是嵌入式处理器、单片机等,及你的代码的时间敏感程度:如时序严格的驱动还是MS,等等因素,自己可以判断使用。还有一点需要强调:使用函数指针是为了获得某种灵活或模型(C++编译器内部大量使用函数指针),所以,这是一种平衡。
用指针优化学生排名(在函数中,用指针实现数据的输入输出以及数组的排序)
说的也不是很具体。
使用链表倒是有点符合要求:
参考:
#include《iostream》
using namespace std;
struct student
{
char name;
float score;
struct student *next;
};
student *search(student *head, float key)
{
student *p;
p = head;
while (p-》next != NULL)
{
if (p-》next-》score 《 key)
break;
p = p-》next;
}
return p;
}
void insert (student *p , student *newp)
{
newp-》next = p-》next;
p-》next = newp;
}
void display(student *head)
{
student *p;
p=head;
while(p-》next != NULL)
{
cout《《p-》next-》name《《"\t"《《p-》next-》score《《endl;
p = p-》next;
}
}
int main()
{
student *newp,*head,*p;
char name;
float score;
int low=60;
if((newp = new student) == NULL)
{
cout《《"the new student is fail"《《endl;
exit(0);
}
head = newp;
head-》next = NULL;
cout《《"input the name and score"《《endl;
cin》》name》》score;
while (score》0)
{
if((newp=new student)==NULL)
{
cout《《"the new student is fail"《《endl;
exit(0);
}
strcpy(newp-》name,name);
newp-》score = score;
newp-》next = NULL;
p = search (head , score);
insert (p , newp);
cin》》name》》score;
}
cout《《"the order is:"《《endl;
display (head);
if(head-》next == NULL)
cout《《"the list has been deleted,or the list is empty"《《endl;
}
C#和java比有什么优势
优势: 1.c#语法简洁,流畅,严谨,比其他的语言更易学习和记忆 2.完善的垃圾回收机制 3.完善的智能提示功能 4.完全面向对象 5.具有更高安全性,稳定性 6.与web结合紧密缺点; 1.c#在windows上像神一样,离开了windows神马也不是,java可以在不同的操作系统上运行,不论win,unix……跨平台性是java的一大特点,但相应的java的执行效率也受到影响,各有取舍。 2.微软的东西与他们自己的产品有很好的的兼容性,与别人的东西,基本不兼容,这也算是微软的一大特色……,c#似乎也有这毛病。 2. B\S逐渐替代C\S结构成为软件开发的主流,对于企业级的web开发,服务器不可能是windows所以服务器端的开发也不会用到c#初学的人,c#似乎更容易上手,在有一定的c#基础情况下学习java,会感觉更轻松点
如何优化你的C代码
一、程序结构的优化1、程序的书写结构虽然书写格式并不会影响生成的代码质量,但是在实际编写程序时还是应该尊循一定的书写规则,一个书写清晰、明了的程序,有利于以后的维护。在书写程序时,特别是对于While、for、do…while、if…elst、switch…case等语句或这些语句嵌套组合时,应采用“缩格”的书写形式,2、标识符程序中使用的用户标识符除要遵循标识符的命名规则以外,一般不要用代数符号(如a、b、x1、y1)作为变量名,应选取具有相关含义的英文单词(或缩写)或汉语拼音作为标识符,以增加程序的可读性,如:count、number1、red、work等。3、程序结构C语言是一种高级程序设计语言,提供了十分完备的规范化流程控制结构。因此在采用C语言设计单片机应用系统程序时,首先要注意尽可能采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,便于调试和维护。于一个较大的应用程序,通常将整个程序按功能分成若干个模块,不同模块完成不同的功能。各个模块可以分别编写,甚至还可以由不同的程序员编写,一般单个模块完成的功能较为简单,设计和调试也相对容易一些。在C语言中,一个函数就可以认为是一个模块。所谓程序模块化,不仅是要将整个程序划分成若干个功能模块,更重要的是,还应该注意保持各个模块之间变量的相对独立性,即保持模块的独立性,尽量少使用全局变量等。对于一些常用的功能模块,还可以封装为一个应用程序库,以便需要时可以直接调用。但是在使用模块化时,如果将模块分成太细太小,又会导致程序的执行效率变低(进入和退出一个函数时保护和恢复寄存器占用了一些时间)。4、定义常数在程序化设计过程中,对于经常使用的一些常数,如果将它直接写到程序中去,一旦常数的数值发生变化,就必须逐个找出程序中所有的常数,并逐一进行修改,这样必然会降低程序的可维护性。因此,应尽量当采用预处理命令方式来定义常数,而且还可以避免输入错误。5、减少判断语句能够使用条件编译(ifdef)的地方就使用条件编译而不使用if语句,有利于减少编译生成的代码的长度,能够不用判断语句则少用判断用语句。6、表达式对于一个表达式中各种运算执行的优先顺序不太明确或容易混淆的地方,应当采用圆括号明确指定它们的优先顺序。一个表达式通常不能写得太复杂,如果表达式太复杂,时间久了以后,自己也不容易看得懂,不利于以后的维护。7、函数对于程序中的函数,在使用之前,应对函数的类型进行说明,对函数类型的说明必须保证它与原来定义的函数类型一致,对于没有参数和没有返回值类型的函数应加上“void”说明。如果果需要缩短代码的长度,可以将程序中一些公共的程序段定义为函数,在Keil中的高级别优化就是这样的。如果需要缩短程序的执行时间,在程序调试结束后,将部分函数用宏定义来代替。注意,应该在程序调试结束后再定义宏,因为大多数编译系统在宏展开之后才会报错,这样会增加排错的难度。8、尽量少用全局变量,多用局部变量。因为全局变量是放在数据存储器中,定义一个全局变量,MCU就少一个可以利用的数据存储器空间,如果定义了太多的全局变量,会导致编译器无足够的内存可以分配。而局部变量大多定位于MCU内部的寄存器中,在绝大多数MCU中,使用寄存器操作速度比数据存储器快,指令也更多更灵活,有利于生成质量更高的代码,而且局部变量所的占用的寄存器和数据存储器在不同的模块中可以重复利用。9、设定合适的编译程序选项许多编译程序有几种不同的优化选项,在使用前应理解各优化选项的含义,然后选用最合适的一种优化方式。通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,可能会影响程序的正确性,导致程序运行出错。因此应熟悉所使用的编译器,应知道哪些参数在优化时会受到影响,哪些参数不会受到影响。在ICCAVR中,有“Default”和“Enable Code Compression”两个优化选项。在CodeVisionAVR中,“Tiny”和“small”两种内存模式。在IAR中,共有7种不同的内存模式选项。在GCCAVR中优化选项更多,一不小心更容易选到不恰当的选项。二、代码的优化1、选择合适的算法和数据结构应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。.选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。数组与指针语句具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。但是在Keil中则相反,使用数组比使用的指针生成的代码更短。。3、使用尽量小的数据类型能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。在ICCAVR中,可以在Options中设定使用printf参数,尽量使用基本型参数(%c、%d、%x、%X、%u和%s格式说明符),少用长整型参数(%ld、%lu、%lx和%lX格式说明符),至于浮点型的参数(%f)则尽量不要使用,其它C编译器也一样。在其它条件不变的情况下,使用%f参数,会使生成的代码的数量增加很多,执行速度降低。4、使用自加、自减指令通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。在AVR单片适用的ICCAVR、GCCAVR、IAR等C编译器以上几种书写方式生成的代码是一样的,也能够生成高质量的inc和dec之类的的代码。5、减少运算的强度可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。如下:(1)、求余运算。a=a%8;可以改为:a=a&7;说明:位操作只需一个指令周期即可完成,而大部分的C编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。通常,只要求是求2n方的余数,均可使用位操作的方法来代替。(2)、平方运算a=pow(a,2.0);可以改为:a=a*a;说明:在有内置硬件乘法器的单片机中(如51系列),乘法运算比求平方运算快得多,因为浮点数的求平方是通过调用子程序来实现的,在自带硬件乘法器的AVR单片机中,如ATMega163中,乘法运算只需2个时钟周期就可以完成。既使是在没有内置硬件乘法器的AVR单片机中,乘法运算的子程序比平方运算的子程序代码短,执行速度快。如果是求3次方,如:a=pow(a,3.0);更改为:a=a*a*a;则效率的改善更明显。(3)、用移位实现乘除法运算a=a*4;b=b/4;可以改为:a=a《《2;b=b》》2;说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。在ICCAVR中,如果乘以2n,都可以生成左移的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:a=a*9可以改为:a=(a《《3)+a6、循环(1)、循环语对于一些不需要循环变量参加运算的任务可以把它们放到循环外面,这里的任务包括表达式、函数的调用、指针运算、数组访问等,应该将没有必要执行多次的操作全部集合在一起,放到一个init的初始化程序中进行。(2)、延时函数:通常使用的延时函数均采用自加的形式:void delay (void){unsigned int i;for (i=0;i《1000;i++);}将其改为自减延时函数:void delay (void){unsigned int i;for (i=1000;i》0;i--);}两个函数的延时效果相似,但几乎所有的C编译对后一种函数生成的代码均比前一种代码少1~3个字节,因为几乎所有的MCU均有为0转移的指令,采用后一种方式能够生成这类指令。在使用while循环时也一样,使用自减指令控制循环会比使用自加指令控制循环生成的代码更少1~3个字母。但是在循环中有通过循环变量“i”读写数组的指令时,使用预减循环时有可能使数组超界,要引起注意。(3)while循环和do…while循环用while循环时有以下两种循环形式:unsigned int i;i=0;while (i《1000){i++;//用户程序}或:unsigned int i;i=1000;doi--;//用户程序while (i》0);在这两种循环中,使用do…while循环编译后生成的代码的长度短于while循环。7、查表在程序中一般不进行非常复杂的运算,如浮点数的乘除及开方等,以及一些复杂的数学模型的插补运算,对这些即消耗时间又消费资源的运算,应尽量使用查表的方式,并且将数据表置于程序存储区。如果直接生成所需的表比较困难,也尽量在启动时先计算,然后在数据存储器中生成所需的表,后以在程序运行直接查表就可以了,减少了程序执行过程中重复计算的工作量。
std::vector中放函数指针,可以用std::find来查找吗
。STL是C++非常宝贵的一部分,提供了许多对C的优化。就像你这里说的vector和指针。vector就安全得多,并且提供了很多方便的操作;使用vector不仅你会出错更少,并且很多烦琐的代码你都不用编写,它都是vector自带的。另外,站长团上有产品团购,便宜有保证
最近写程序是用到指针,我本来想再一个函数中定义静态指针,以为可以向静态变量一样在每次进入程序时指针
如果一定要用静态指针的话,就把静态变量(如static char *p)声明在文件头部,头文件包含之后,而不是函数中。因为在每次进入函数时静态变量都会被重新定义一次,如果你不对其初始化,则系统每次的分配给它的值都是随机的 全局指针(如extern char *p)作用域是整个工程,即整个工程中不同的文件都可以调用它。一般定义在文件首部,必须在函数之外; 静态指针(static char *p)作用域是一个文件内部,即在文件中定义的各个函数都可以调用它,但其他文件不能调用。一般定义在文件首部,必须在函数之外; 一般指针(char *p)作用域是一个函数内部,即它的定义赋值及使用都在函数内部进行,当进入函数时,指针被定义;当退出函数时,指针变量就会被删除。定义在函数内部。 另外,无论是extern, static还是一般指针变量,只要是在函数中定义的,它的生存周期都在函数内部,当进入函数时,指针被定义;当退出函数时,无论它是什么类型的指针变量,都会被删除。
请问C语言高手:指向函数的指针(*p)(),p的值能不能用scanf输入呢为什么不行前面用int和char有区别吗
p表示的是指针指向的地址,这个如果在程序中没有指定它指向的内存空间,是不能用scanf输入的如果指向了一段内容空间,比如int a;int *p=a; 这样的话就可以用scanf输入了而指向函数的指针应该没有给定这样空间指向所以不能把int和char是什么,函数返回值还是指针类型?
本文相关文章:
net混淆工具(.net软件,用什么软件加密狗加密,能防止代码反编译)
2024年9月7日 10:05
java编译找不到符号怎么解决(Java编译错误:找不到符号)
2024年9月6日 18:45
编译器工作的五个步骤(在编译过程中,进行类型分析和检查是( )阶段一个主要工作)
2024年9月6日 10:40
编译和解释的区别是什么?Java源文件和编译后的文件扩展名分别为
2024年9月1日 10:30
tc编译器怎么用啊,有知道的没?TC3.0、TC2.0、VC6.0分别什么区别阿
2024年8月27日 06:40
compileerror的意思(一个程序编译通过了 但在acm系统下提示compile error)
2024年8月24日 15:40
dll文件可以看到源代码吗(问一下高手 c++dll文件如何反编译 看源代码啊)
2024年8月23日 15:15
excel activex控件(Excel插入Activex控件,提示编译错误,缺少:语句结束代码有问题吗)
2024年8月14日 15:50
python编译成二进制(python的程序可以编译成二进制可执行文件么)
2024年8月7日 00:00
vs2019编译器下载(使用vs2019如何只编译一个c++文件)
2024年8月1日 01:55
有哪些防止反编译 Java 类库 jar 文件的办法?android app怎么防止反编译
2024年7月19日 04:45
strchr函数用法返回值(C中的strchr函数怎么使用 我百度上找的代码都过不了编译语言)
2024年7月12日 04:17
qt添加msvc编译器(QT中如何把msvc编译器换成mingw编译器)
2024年7月12日 00:14
vbscript学习工具(微软公司出品的一套可视化编程工具, 语法基于Basic. 脚本语言, 就是不编译成二进制)
2024年7月11日 22:11
更多文章:
手机字体ttf下载(vivoy97手机如何下载ttf字体安装字体)
2024年6月21日 03:37
t20天正建筑官网下载(天正建筑2019过期补丁哪里可以下载,求数据包一份,要可以用的,小弟万分感谢)
2024年6月15日 21:10
鬼泣5 3dm(《鬼泣5》、《只狼》即将上线,新年还有什么值得期待的游戏大作)
2024年6月12日 16:06
怎样把炮炮兵的动态头像设置成自己的头像?我找了个炮炮兵的动态图片,想把它作为QQ头像怎么办(我不是QQ会员)
2024年3月20日 19:05
微信怎么借钱马上到账(微信怎么借钱马上到账 这些平台来助攻)
2024年7月26日 20:25
u盘识别不出来解决方法 修复(u盘在电脑上读不出来怎么修复)
2024年4月11日 18:20