关于C++在运算处理方式上的几个疑问

dianyancao 2014-09-01 02:00:51
C++的数(域)值运算有时和代数运算的结果不同
是否可以通过对编译选项做出一些断言,来使得编译器对某些运算发出警告

C++中的数组,写入时可能产生越界
是否可以通过设置编译选项,使得编译器发出警告

C++对于某些代码的优化,比较保守
是否可以通过等价的变换代码(算法),使得对于任意输入输出结果保持不变,并且提高计算效率
...全文
303 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
dianyancao 2014-09-02
  • 打赏
  • 举报
回复
没有找到lin.bat批处理文件,已经运行过配置向导了..
dianyancao 2014-09-02
  • 打赏
  • 举报
回复
引用 30 楼 truelance 的回复:
http://download.csdn.net/detail/lingyin55/3421037 从这里下一个吧
thanks,这个工具也能检查QT的C++源代码文件吗?
dianyancao 2014-09-02
  • 打赏
  • 举报
回复
引用 29 楼 truelance 的回复:
你这种做法叫误报,那大部分代码行都会报告警。 报了告警仍然需要人来检查和修改。实际使用的统计,误报大于70%的检查结果基本上没有人看。工具必须在漏报和误报之间做一个折中。
也就是说PC-Lint可能也会产生很多误报? 已下载,大概知道怎么用,检查完整的一个工程,用lint-nt.exe参数要怎么写?
wanght99 2014-09-01
  • 打赏
  • 举报
回复
引用 9 楼 truelance 的回复:
[quote=引用 6 楼 dianyancao 的回复:] [quote=引用 4 楼 FancyMouse 的回复:] 你的代码里会有很多的assumption,编译器是不知道的。在不知道这些assumption的时候很多你认为等价的东西编译器都觉得不等价。
引用 1 楼 truelance 的回复:
另外高级语言的编译器优化无法达到人工汇编级优化的水平,对特定的代码优化可以直接用内嵌汇编解决。
引用 2 楼 wanght99 的回复:
通过等价变化代码来提高计算效率是可行的, 不过前提是代码本身还有优化的空间, 万灵药是不存在的 :)
嗯,有没有类似#assume的方法,声明这些断言,为编译器的优化指明方向呢[/quote] c里的关键字register, strict, volatile等都是为优化设计的 预编译有#pragma。(比如可以定义哪个case分支进入的概率更大, 哪些全局变量访问的更频繁), 但是除了少数参数,大部分优化选项是每个编译器自己定义的,没有通用性[/quote] 同意, 我觉得严格地说inline也算, 另外个人认为指望编译器优化空间终究有限, 大幅度的优化还是要从数据结构, 代码逻辑, 甚至汇编的方面去做.
熊熊大叔 2014-09-01
  • 打赏
  • 举报
回复
引用 6 楼 dianyancao 的回复:
[quote=引用 4 楼 FancyMouse 的回复:] 你的代码里会有很多的assumption,编译器是不知道的。在不知道这些assumption的时候很多你认为等价的东西编译器都觉得不等价。
引用 1 楼 truelance 的回复:
另外高级语言的编译器优化无法达到人工汇编级优化的水平,对特定的代码优化可以直接用内嵌汇编解决。
引用 2 楼 wanght99 的回复:
通过等价变化代码来提高计算效率是可行的, 不过前提是代码本身还有优化的空间, 万灵药是不存在的 :)
嗯,有没有类似#assume的方法,声明这些断言,为编译器的优化指明方向呢[/quote] c里的关键字register, strict, volatile等都是为优化设计的 预编译有#pragma。(比如可以定义哪个case分支进入的概率更大, 哪些全局变量访问的更频繁), 但是除了少数参数,大部分优化选项是每个编译器自己定义的,没有通用性
赵4老师 2014-09-01
  • 打赏
  • 举报
回复
引用 7 楼 dianyancao 的回复:
[quote=引用 5 楼 zhao4zhong1 的回复:] 判断是否越界访问,可以在数组的最后一个元素之后对应的地址处设置数据读写断点。
越界访问可能发生在内存的任何位置,上述方法只能检查一个位置呀[/quote] 崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 其实电脑开机后物理内存的每个字节都是可读写的,从来不会因为所谓的new、delete或malloc、free而被创建、销毁。区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。
dianyancao 2014-09-01
  • 打赏
  • 举报
回复
引用 5 楼 zhao4zhong1 的回复:
判断是否越界访问,可以在数组的最后一个元素之后对应的地址处设置数据读写断点。
越界访问可能发生在内存的任何位置,上述方法只能检查一个位置呀
dianyancao 2014-09-01
  • 打赏
  • 举报
回复
引用 4 楼 FancyMouse 的回复:
你的代码里会有很多的assumption,编译器是不知道的。在不知道这些assumption的时候很多你认为等价的东西编译器都觉得不等价。
引用 1 楼 truelance 的回复:
另外高级语言的编译器优化无法达到人工汇编级优化的水平,对特定的代码优化可以直接用内嵌汇编解决。
引用 2 楼 wanght99 的回复:
通过等价变化代码来提高计算效率是可行的, 不过前提是代码本身还有优化的空间, 万灵药是不存在的 :)
嗯,有没有类似#assume的方法,声明这些断言,为编译器的优化指明方向呢
赵4老师 2014-09-01
  • 打赏
  • 举报
回复
判断是否越界访问,可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断,可将数组多声明一个元素,并设置数据读写断点在该多出元素对应的地址上。
#include <time.h>
#include <stdlib.h>
#include <windows.h>
int main() {
    int a,b[11];//本来是b[10],为判断哪句越界,故意声明为b[11]

    srand((unsigned int)time(NULL));//按两次F11,等黄色右箭头指向本行时,调试、新建断点、新建数据断点,地址:&b[10],字节计数:4,确定。
    while (1) {//按F5,会停在下面某句,此时a的值为10,b[10]已经被修改为对应0..4之一。
        b[(a=rand()%11)]=0;
        Sleep(100);
        b[(a=rand()%11)]=1;
        Sleep(100);
        b[(a=rand()%11)]=2;
        Sleep(100);
        b[(a=rand()%11)]=3;
        Sleep(100);
        b[(a=rand()%11)]=4;
        Sleep(100);
    }
    return 0;
}
http://bbs.csdn.net/topics/390676437
熊熊大叔 2014-09-01
  • 打赏
  • 举报
回复
引用 27 楼 dianyancao 的回复:
[quote=引用 25 楼 truelance 的回复:] http://www.gimpel.com/html/manual.pdf
这本书的1.2.3.4章好像都没了,看running test program应该到哪里找?[/quote] http://download.csdn.net/detail/lingyin55/3421037 从这里下一个吧
FancyMouse 2014-09-01
  • 打赏
  • 举报
回复
你的代码里会有很多的assumption,编译器是不知道的。在不知道这些assumption的时候很多你认为等价的东西编译器都觉得不等价。
熊熊大叔 2014-09-01
  • 打赏
  • 举报
回复
引用 26 楼 dianyancao 的回复:
[quote=引用 25 楼 truelance 的回复:] 但是并不是在任何时候,静态检查都能知道这个参数值可能的取值范围。除非你的程序没有任何和外部的交互,仅仅是根据全局变量的初始值然后进行一个固定计算这样的简单程序。 http://www.gimpel.com/html/manual.pdf
这时的index定义域就是int的定义域[-2^31,2^31-1]了啊,这时如果是任意输入,并且在上下文中没有检查 很可能会发生越界的危险,如果这个函数不是私有,而是公有的,那么还是可以提示警告啊[/quote] 你这种做法叫误报,那大部分代码行都会报告警。 报了告警仍然需要人来检查和修改。实际使用的统计,误报大于70%的检查结果基本上没有人看。工具必须在漏报和误报之间做一个折中。
勤奋的小游侠 2014-09-01
  • 打赏
  • 举报
回复
c++的优点就是灵活,可以让用用直接操作内存。 缺点就是因为用户可以直接操作内存,所以会有数组越界的问题发生。 如果编译器一些功能不允许数组越界,必然也会将其它的一些内存操作也禁锢掉,也就失去了它对内存操作的灵活性。 这样就退化成其它的语言了。
wanght99 2014-09-01
  • 打赏
  • 举报
回复
引用 2 楼 wanght99 的回复:
[quote=引用 楼主 dianyancao 的回复:] C++的数(域)值运算有时和代数运算的结果不同 是否可以通过对编译选项做出一些断言,来使得编译器对某些运算发出警告 C++中的数组,写入时可能产生越界 是否可以通过设置编译选项,使得编译器发出警告 C++对于某些代码的优化,比较保守 是否可以通过等价的变换代码(算法),使得对于任意输入输出结果保持不变,并且提高计算效率
1, 编译检查只能检查编译时能看到的东西, 除非是常量, 否则每一次运算都有溢出的可能, 编译器不大可能对这种情况发出警告. 2, 同理, 如果是以变量作为下标, 编译器无法发现可能的越界. 因为编译器根本不知道运行时下标是几. 总的来说这些错误编译器可以做一定的检测, 但大多数情况下编译器无能为力. 这方面不能过度依赖编译器. 3, 我认为"C++对某些代码优化比较保守"是伪命题, 优化是编译器做的事情, 而不同的编译器的优化策略不同, g++确实偏保守, 但Intel的ICC优化程度就比g++高, 而且像楼上说的, 每个编译器都有不同的优化选项. 通过等价变化代码来提高计算效率是可行的, 不过前提是代码本身还有优化的空间, 万灵药是不存在的 :)[/quote] 措辞失误, "编译器无法发现可能的越界"太绝对了, 但编译器确实无法发现所有可能的越界.
wanght99 2014-09-01
  • 打赏
  • 举报
回复
引用 楼主 dianyancao 的回复:
C++的数(域)值运算有时和代数运算的结果不同 是否可以通过对编译选项做出一些断言,来使得编译器对某些运算发出警告 C++中的数组,写入时可能产生越界 是否可以通过设置编译选项,使得编译器发出警告 C++对于某些代码的优化,比较保守 是否可以通过等价的变换代码(算法),使得对于任意输入输出结果保持不变,并且提高计算效率
1, 编译检查只能检查编译时能看到的东西, 除非是常量, 否则每一次运算都有溢出的可能, 编译器不大可能对这种情况发出警告. 2, 同理, 如果是以变量作为下标, 编译器无法发现可能的越界. 因为编译器根本不知道运行时下标是几. 总的来说这些错误编译器可以做一定的检测, 但大多数情况下编译器无能为力. 这方面不能过度依赖编译器. 3, 我认为"C++对某些代码优化比较保守"是伪命题, 优化是编译器做的事情, 而不同的编译器的优化策略不同, g++确实偏保守, 但Intel的ICC优化程度就比g++高, 而且像楼上说的, 每个编译器都有不同的优化选项. 通过等价变化代码来提高计算效率是可行的, 不过前提是代码本身还有优化的空间, 万灵药是不存在的 :)
dianyancao 2014-09-01
  • 打赏
  • 举报
回复
引用 25 楼 truelance 的回复:
http://www.gimpel.com/html/manual.pdf
这本书的1.2.3.4章好像都没了,看running test program应该到哪里找?
熊熊大叔 2014-09-01
  • 打赏
  • 举报
回复
1/2, 有工具pclint, covertity等干这个事情,一般大公司,c++代码要求用pclint检查是强制的 3, c++代码优化由编译选项-o确定是保守还是激进,有o0,o1,o2,o3 4级。大公司可能自己还会对编译器进行定制优化。另外高级语言的编译器优化无法达到人工汇编级优化的水平,对特定的代码优化可以直接用内嵌汇编解决。
dianyancao 2014-09-01
  • 打赏
  • 举报
回复
引用 25 楼 truelance 的回复:
但是并不是在任何时候,静态检查都能知道这个参数值可能的取值范围。除非你的程序没有任何和外部的交互,仅仅是根据全局变量的初始值然后进行一个固定计算这样的简单程序。 http://www.gimpel.com/html/manual.pdf
这时的index定义域就是int的定义域[-2^31,2^31-1]了啊,这时如果是任意输入,并且在上下文中没有检查 很可能会发生越界的危险,如果这个函数不是私有,而是公有的,那么还是可以提示警告啊
熊熊大叔 2014-09-01
  • 打赏
  • 举报
回复
引用 18 楼 dianyancao 的回复:
[quote=引用 16 楼 truelance 的回复:] 编译器不可能预见所有情况,因为越界检查与图灵停机问题同构。
比如函数 int at(int array[10],int index) { return array[index]; } 在编译期,应该可以通过得到index的定义域,来证明函数at绝对不发生越界 相应的index的定义域可以用if来定义,当使用了if的上下文使得index的值饱和在0-9之间的整数 这时就可以证明这里at的使用绝对不发生越界?[/quote] 以pclint为例吧。 按你写的这个例子是不会检查的,因为参数中的数组大小是无意义的。 我们假设int array[10];是一个全局数组。 那pclint确实会检查,当某个函数调用at()且传入的参数index的值可能大于等于10时报告warning. 但是并不是在任何时候,静态检查都能知道这个参数值可能的取值范围。除非你的程序没有任何和外部的交互,仅仅是根据全局变量的初始值然后进行一个固定计算这样的简单程序。否则静态检查不可能知道人将要在IO界面输入的参数是多少,也不可能知道别的程序将要发过来的消息中的值是多少,或者读取的文件、数据库中的值是多少。 你可以从网上下载一个pclint的手册,然后看一下value tracking这一章是怎样处理的,对你的理解会有所帮助。 http://www.gimpel.com/html/manual.pdf
dianyancao 2014-09-01
  • 打赏
  • 举报
回复
引用 21 楼 wanght99 的回复:
[quote=引用 12 楼 dianyancao 的回复:] [quote=引用 9 楼 truelance 的回复:] 编译器只能在保证结果一致的情况下, 非常细微的改动都有可能导致结果不完全一致. 更别说"数学公式"这种东西了. 计算机程序跟数学终究不是一个东西.
是的,这个是关于数学表达式的化简了,也许编译器没有保存或提供这些知识
加载更多回复(13)

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧