今天调试代码,定位一个compiler 死循环问题。 最终定位出来的原因给作者在下面这篇文章中总结的基本一样。需要指出的是这是程序员及其容易犯的一个错误。忘记将std::list的成员函数erase 返回给iter 本身。这样导致iter 成为类似野指针(虽然iter 不是指针,但是本质上是包裹起来的指针),行为将变得undefined。 如果在某些平台上,比如Linux,操作系统没有立即回收内存,有可能该问题本隐藏起来。但是在其他立即回收内存(或硬删除而不是移动到缓存)的平台上,则会造成死循环。
下面是问题代码,及修复代码:
//这里假设上下文已经设置好了myList (有了元素)
// str 是作为函数入参数传进来, const char * 类型
原代码 (错误使用方法3,相对于下面链接中的两种错误方法) :
std::list<const char *>::iterator myList ;
for(std::list<const char *>::iterator I = myList.begin(), E = myList.end(); I != E; ++I) {
if (!strcmp(*I, str)) {
_myList.erase(I);
--I;
}
}
修复代码 (正确使用方法3,相对于下面链接中的两种正确方法):
std::list<const char *>::iterator myList ;
for(std::list<const char *>::iterator I = myList.begin(), E = myList.end(); I != E; ++I) {
if (!strcmp(*I, str)) {
I = _myList.erase(I);
--I;
}
}
// comment : erase 返回指向删除元素下一个位置元素的指针,先-- 在++,仍正确指向
// 删除元素的下一个位置,可以正常工作。
另外两种错误及正确方法,见下面的链接。 个人比较喜欢正确方法三,虽然需要强制--,再++,但是毕竟避免了把++操作从for () 语句中移动到句外的情况。
总而言之,凡是让程序员记着干某些事情的设计都不是好设计。因为他们总是忘记。 比如这里的让他们记得把erase()返回值付给iter 本身,以及记得new 了以后一定要delete。正如用auto_ptr 或Java 自动垃圾回收方法可以解决到处泛滥的内存泄露问题。或许我们也应该设计一种方法,让erase() 接口不用强求程序员记着赋值给iter。 强制给出void,并让iter 自动指向下个元素也不是一个好方法。程序员使用不当的话,有可能导致跳过元素。笔者没有什么好的idea。如果各位路过的大神,有什么好的想法,欢迎留言讨论。
http://blog.csdn.net/lanbing510/article/details/8796048
下面材料整理自Internet&著作。
STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list、set、map)。在使用erase方法来删除元素时,需要注意一些问题。
在使用 list、set 或 map遍历删除某些元素时可以这样使用:
或
下面是两个错误的使用方法:
或
正确使用方法1:通过erase方法的返回值来获取下一个元素的位置
正确使用方法2:在调用erase方法之前先使用 “++”来获取下一个元素的位置
错误使用方法1:在调用erase方法之后使用“++”来获取下一个元素的位置,由于在调用erase方法以后,该元素的位置已经被删除,如果在根据这个旧的位置来获取下一个位置,则会出现异常。
错误使用方法2:同上。
Friday, 30 September 2016
Thursday, 29 September 2016
fprintf ,printf 及sprintf的使用方法及区别
有时我们用printf 打印调试,发现printf 打印到一半停止,这时候就需要使用fprintf(stderr) 了,因为这么不会缓存,printf 打印之前 通常会有一个缓存,这样会造成内容丢失。 使用fprintf(file)也行。 因为printf 只能打印到stdout,而fprintf 则是指定输出对象,stderr,file 等等。大多数情况下printf 够用。但是当printf不够用时,无法打印出 全部log时,这时候就该fprintf 上场了。
下面是从网上找到的fprintf ,printf 及sprintf的使用方法及区别。
1: fprintf()
#include <stdio.h>
int fprintf( FILE *stream, const char *format, ... );
fprintf()函数根据指定的format(格式)发送信息(参数)到由stream(流)指定的文件.因此fprintf()可以使得信息输出到指定的文件.比如
char name[20] = "Mary";
FILE *out;
out = fopen( "output.txt", "w" );
if( out != NULL )
fprintf( out, "Hello %s\n", name );
对于其输出格式参数,和printf()一样.
fprintf()和printf()一样工作. fprintf()的返回值是输出的字符数,发生错误时返回一个负值.
在有些地方,有这样的定义:printf(...)=fprintf(stdout,...).
2:eg)
fprintf函数的用法!2007-12-13 21:46
fprintf是用于文件操作的,原型是int fprintf( FILE *stream, const char *format [, argument ]...);
举例用法:
#include <stdio.h>
#include <process.h>
FILE *stream;
void main( void )
{
int i = 10;
double fp = 1.5;
char s[] = "this is a string";
char c = '\n';
stream = fopen( "fprintf.out", "w" );
fprintf( stream, "%s%c", s, c );
fprintf( stream, "%d\n", i );
fprintf( stream, "%f\n", fp );
fclose( stream );
system( "type fprintf.out" );
}
屏幕输出:
this is a string
10
1.500000
printf就是在屏幕打印出一段字符串来啊
原型是int printf( const char *format [, argument]... );
是标准输出。
3:printf、sprintf与fprintf 的用法区分
1.printf 是和标准输出文件(stdout)关联的,fprintf 则没有这个限制.
2.fprintf是用于文件操作的,原型是int fprintf( FILE *stream, const char *format [, argument ]...);
3.sprintf是格式化输出到一个字符串,fprintf是格式化输出到一个stream,通常是到文件。
int fprintf( FILE *stream, const char *format [, argument ]...);
int sprintf( char *buffer, const char *format [, argument] ... )
下面是从网上找到的fprintf ,printf 及sprintf的使用方法及区别。
1: fprintf()
#include <stdio.h>
int fprintf( FILE *stream, const char *format, ... );
fprintf()函数根据指定的format(格式)发送信息(参数)到由stream(流)指定的文件.因此fprintf()可以使得信息输出到指定的文件.比如
对于其输出格式参数,和printf()一样.
fprintf()和printf()一样工作. fprintf()的返回值是输出的字符数,发生错误时返回一个负值.
在有些地方,有这样的定义:printf(...)=fprintf(stdout,...).
2:eg)
fprintf函数的用法!2007-12-13 21:46
fprintf是用于文件操作的,原型是int fprintf( FILE *stream, const char *format [, argument ]...);
举例用法:
#include <stdio.h>
#include <process.h>
FILE *stream;
void main( void )
{
int i = 10;
double fp = 1.5;
char s[] = "this is a string";
char c = '\n';
stream = fopen( "fprintf.out", "w" );
fprintf( stream, "%s%c", s, c );
fprintf( stream, "%d\n", i );
fprintf( stream, "%f\n", fp );
fclose( stream );
system( "type fprintf.out" );
}
屏幕输出:
this is a string
10
1.500000
printf就是在屏幕打印出一段字符串来啊
原型是int printf( const char *format [, argument]... );
是标准输出。
3:printf、sprintf与fprintf 的用法区分
1.printf 是和标准输出文件(stdout)关联的,fprintf 则没有这个限制.
2.fprintf是用于文件操作的,原型是int fprintf( FILE *stream, const char *format [, argument ]...);
3.sprintf是格式化输出到一个字符串,fprintf是格式化输出到一个stream,通常是到文件。
int
int
file命令
转载:http://www.cnblogs.com/kerrycode/p/3806618.html
命令简介:
该命令用来识别文件类型,也可用来辨别一些文件的编码格式。它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的。
执行权限 :All User
指令所在路径:/usr/bin/file
命令语法:
file [ -bchikLnNprsvz ] [ -f namefile ] [ -F separator ] [ -m magicfiles ] file ...
命令参数:
下表列出了部分常用的参数。
参数 | 长参数 | 描叙 |
-b | 列出文件辨识结果时,不显示文件名称。 | |
-c | 详细显示指令执行过程,便于排错或分析程序执行的情形 | |
-f | 列出文件中文件名的文件类型 | |
-F | 使用指定分隔符号替换输出文件名后的默认的“:”分隔符。 | |
-i | 输出mime类型的字符串 | |
-L | 查看对应软链接对应文件的文件类型 | |
-z | 尝试去解读压缩文件的内容 | |
--help | 显示命令在线帮助 | |
--version | 显示命令版本信息 |
使用示例:
1:查看file命令的帮助信息
[root@DB-Server ~]# file --help
Usage: file [OPTION]... [FILE]...
Determine file type of FILEs.
-m, --magic-file LIST use LIST as a colon-separated list of magic
number files
-z, --uncompress try to look inside compressed files
-b, --brief do not prepend filenames to output lines
-c, --checking-printout print the parsed form of the magic file, use in
conjunction with -m to debug a new magic file
before installing it
-f, --files-from FILE read the filenames to be examined from FILE
-F, --separator string use string as separator instead of `:'
-i, --mime output mime type strings
-k, --keep-going don't stop at the first match
-L, --dereference causes symlinks to be followed
-n, --no-buffer do not buffer output
-N, --no-pad do not pad output
-p, --preserve-date preserve access times on files
-r, --raw don't translate unprintable chars to \ooo
-s, --special-files treat special (block/char devices) files as
ordinary ones
--help display this help and exit
--version output version information and exit
2:查看文件类型
例如,如下所示,Temp.txt 文件类型为text,编码为UTF-8 Unicode
[root@DB-Server ~]# file Temp.txt
Temp.txt: UTF-8 Unicode text, with very long lines, with CRLF line terminators
通过下面两个命令对时,就可以清晰的了解参数-b的作用。
[root@DB-Server ~]# file Temp.txt
Temp.txt: UTF-8 Unicode text, with very long lines, with CRLF line terminators
[root@DB-Server ~]# file -b Temp.txt
UTF-8 Unicode text, with very long lines, with CRLF line terminators

4: 输出mime类型的字符串
[root@DB-Server ~]# file -i Temp.txt
Temp.txt: text/plain; charset=utf-8
5: 查看文件中的文件名的文件类型
这个参数非常适合shell脚本去查找、判别某种文件类型的数据。
[root@DB-Server ~]# cat >test
/root/install.log
it is only one test file
[2]+ Stopped cat > test
[root@DB-Server ~]# file -f test
/root/install.log: ASCII text
it is only one test file: ERROR: cannot open `it is only one test file' (No such file or directory)
[root@DB-Server ~]#
[root@DB-Server ~]#

5: 使用指定分隔符号替换输出文件名后的默认的“:”分隔符。
感觉这个参数很鸡肋!我搞明白这个参数的作用时,很是纳闷。

6:尝试去解读压缩文件的内容
[root@DB-Server ~]# file -z Temp.txt.gz
Temp.txt.gz: UTF-8 Unicode text, with very long lines, with CRLF line terminators (gzip compressed data, was "Temp.txt", from Unix, last modified: Tue Jun 24 00:34:15 2014)
[root@DB-Server ~]#
7: 查看软链接对应文件的文件类型
如下所示,创建一个软链接sfile,然后分别用file 和带参数的file -L查看
[root@DB-Server ~]# ln -s Temp.txt.gz sfile
[root@DB-Server ~]# file sfile
sfile: symbolic link to `Temp.txt.gz'
[root@DB-Server ~]# file -L sfile
sfile: gzip compressed data, was "Temp.txt", from Unix, last modified: Tue Jun 24 00:34:15 2014
[root@DB-Server ~]#
Tuesday, 27 September 2016
程序员修炼之道读书笔记 31 Bend or Break (弯还是折?
将数据模型和视图分开。
好的代码,模块清晰,功能明确。烂代码完全一锅粥,改一处牵连一堆问题,牵一发而动全身。完全没法维护,熵极高。如果你的代码是这样的,那么是时候重构拆分了。
Monday, 26 September 2016
程序员修炼之道读书笔记 30 Finish What you Start
分配资源的函数或对象,同时应该负责释放资源。不要推迟到另外一个函数或对象去释放。这样容易造成潜在隐患。
比如在一个函数中open file 或者new 空间,也应该在该函数中close file 或
delete
空间。
whoever allocates a resource should be responsible for
deallocating it。
Some C and C++
developers make a point of setting a pointer to NULL after they deallocate the
memory it references. This is a good idea.
Because this will prevent refer(deference) to this
pointer later, which will cause runtime error.
Sunday, 25 September 2016
程序员修炼之道读书笔记 29 不要以为你的假设总是无条件成立
一分钟不一定60秒,因为有闰秒的情况 (可以为61秒或62秒)。
三角形内角和也不定是180度,因为有非欧几里得的几何。
C++/Java 中,
a+1
不一定小于a ,因为会有溢出的情况。
阳历一个月也可能有出现小于28天的情况,1972年9月只有19天,为日历同步而进行的调整。
列举上面的例子,只为说明一个问题,程序员在编程时候,不要自作聪明的以为,某些假设是放之四海皆准的。
总有你想不到或者不知道的情况。为了安全起见,加上assertion验证你的假设,总是防御性编程的一种好方法。
Subscribe to:
Posts (Atom)