0%

no segmentation fault does not means program code is fine

分配页策略,no segmentation fault does not means program code is fine

​ The OS will not allocate partial pages to a program。So some illegal access may not cause some error info. The reason are:

​ 操作系统不会将不完整的页分配给程序,例如,如果要运行的程序总共大约有10000字节,如果完全加载,会占用3个内存页(一个页占4096个字节),它不会仅占用2.5个页,因为页是虚拟内存系统能够操作的最小内存单元,这是调试时要着重了解的情况,这也导致了程序的一些错误内存访问不会触发段错误,换言之,在调试会话期间,没有引起段错误并不能直接说明代码是没有问题的。

Linux的语言设置

Ubuntu

配置文件在/etc/default/locale中。

CentOS

配置文件在/etc/sysconfig/i18n。

修改方法

将 LANG=”zh_CN.UTF-8″ LANGUAGE=”zh_CN:zh”
修改为:LANG=”en_US.UTF-8″ LANGUAGE=”en_US:en”
或者相反。
如果在ssh中中文乱码,可以讲UTF-8改为GB18030。

Linux ln 命令

ln 命令是一个非常重要的命令,可以为某一个文件或目录在其他不同的位置建立一个同步的链接。部分功能与Windows的快捷方式类似。但更加强大。

官方解释为:

ln - make links between files

当我们需要在不同的目录,或者不同的工程,甚至是不同的人员需要用到同一个文件的时候,此时不需要每个位置都通过cp来拷贝一份,因为在源文件更新的时候,这个文件是不会同步更新的 。而此时ln命令就不一样了,通过该命令链接到源文件或目录,不仅可以不用占用重复的更多的磁盘空间,还可以同步更新。NICE

使用格式

1
$ ln [参数][源文件或目录][目标文件或目录]

其中参数的格式为

  • -b ,或 like –backup but does not accept an argument
  • -f,或 --force : 强制执行,这个在链接已经存在的情况下必用
  • -s,或 --symbolic:创建符号链接

在Linux文件系统中,又有两种链接类型:

  1. 硬链接(hard link)
  2. 软链接(symbolic link):又称符号链接,类似于Windows的快捷方式

硬链接会复制一份相同大小的源文件,而软链接是一种特殊的文件,占用很小的磁盘空间。

创建硬链接

默认情况下,不加任何参数,创建的是硬链接,如下,创建源文件a.log的硬链接a1.log

1
2
3
4
5
$ ln a.log a1.log

$ ll
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a.log
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a1.log

这个时候修改源文件a.log的部分内容,可以看到硬链接也同步更新。

1
2
3
4
5
$ vim a.log

$ ll
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a.log
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a1.log

创建软链接

如果需要创建软链接,就需要参数-s,如下,创建源文件a.log的软链接a1.log

1
2
3
4
5
$ ln -s a.log a1.log

$ ll
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 a1.log -> a.log

这个时候修改源文件a.log的部分内容,可以看到软链接没有更新,不过其指向的内容依然更新了。

1
2
3
4
5
$ vim a.log

$ ll
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 a1.log -> a.log

此时可以看到,对于软链接a1.log而言,其仅为一个符号链接,用file看一下:

1
2
$ file a1.log
a1.log: symbolic link to `a.log'

删除源文件后的情况

此时通过ln创建a.log的硬链接ah.log和软链接as.log,然后看一下如果删除源文件会发生什么情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建软硬链接
$ ln a.log ah.log
$ ln -s a.log as.log
$ ll
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 as.log -> a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log

# 删除源文件
$ rm a.log

# 此时如果有颜色显示,as.log应该会是红色的警告色
$ ll
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 as.log -> a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log

# 此时看一下as.log的状态
$ file as.log
as.log: broken symbolic link to `a.log'

可以看到如果删除了源文件,硬链接不受影响,但是软链接已经提示链接损坏了。

强制更新软链接

在软链接存在的情况下,如果再创建一个同名的,会报错,此时就需要强制创建了,加上-f参数即可。

1
2
3
4
5
6
7
8
9
10
11
$ ln -s b.log as.log
ln: failed to create symbolic link 'as.log': File exists

# 强制创建
$ ln -sf b.log as.log

$ ll
-rw-rw-r--. 1 user user 85716 Apr 5 22:16 a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log
lrwxrwxrwx. 1 user user 5 Apr 5 22:21 as.log -> b.log
-rw-rw-r--. 1 user user 85716 Apr 5 22:17 b.log

Linux ln 命令

ln 命令是一个非常重要的命令,可以为某一个文件或目录在其他不同的位置建立一个同步的链接。部分功能与Windows的快捷方式类似。但更加强大。

官方解释为:

ln - make links between files

当我们需要在不同的目录,或者不同的工程,甚至是不同的人员需要用到同一个文件的时候,此时不需要每个位置都通过cp来拷贝一份,因为在源文件更新的时候,这个文件是不会同步更新的 。而此时ln命令就不一样了,通过该命令链接到源文件或目录,不仅可以不用占用重复的更多的磁盘空间,还可以同步更新。NICE

使用格式

1
$ ln [参数][源文件或目录][目标文件或目录]

其中参数的格式为

  • -b ,或 like –backup but does not accept an argument
  • -f,或 --force : 强制执行,这个在链接已经存在的情况下必用
  • -s,或 --symbolic:创建符号链接

在Linux文件系统中,又有两种链接类型:

  1. 硬链接(hard link)
  2. 软链接(symbolic link):又称符号链接,类似于Windows的快捷方式

硬链接会复制一份相同大小的源文件,而软链接是一种特殊的文件,占用很小的磁盘空间。

创建硬链接

默认情况下,不加任何参数,创建的是硬链接,如下,创建源文件a.log的硬链接a1.log

1
2
3
4
5
$ ln a.log a1.log

$ ll
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a.log
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a1.log

这个时候修改源文件a.log的部分内容,可以看到硬链接也同步更新。

1
2
3
4
5
$ vim a.log

$ ll
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a.log
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a1.log

创建软链接

如果需要创建软链接,就需要参数-s,如下,创建源文件a.log的软链接a1.log

1
2
3
4
5
$ ln -s a.log a1.log

$ ll
-rw-rw-r--. 3 user user 85710 Apr 5 21:29 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 a1.log -> a.log

这个时候修改源文件a.log的部分内容,可以看到软链接没有更新,不过其指向的内容依然更新了。

1
2
3
4
5
$ vim a.log

$ ll
-rw-rw-r--. 3 user user 85716 Apr 5 21:34 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 a1.log -> a.log

此时可以看到,对于软链接a1.log而言,其仅为一个符号链接,用file看一下:

1
2
$ file a1.log
a1.log: symbolic link to `a.log'

删除源文件后的情况

此时通过ln创建a.log的硬链接ah.log和软链接as.log,然后看一下如果删除源文件会发生什么情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建软硬链接
$ ln a.log ah.log
$ ln -s a.log as.log
$ ll
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 a.log
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 as.log -> a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log

# 删除源文件
$ rm a.log

# 此时如果有颜色显示,as.log应该会是红色的警告色
$ ll
lrwxrwxrwx. 1 user user 5 Apr 5 21:30 as.log -> a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log

# 此时看一下as.log的状态
$ file as.log
as.log: broken symbolic link to `a.log'

可以看到如果删除了源文件,硬链接不受影响,但是软链接已经提示链接损坏了。

强制更新软链接

在软链接存在的情况下,如果再创建一个同名的,会报错,此时就需要强制创建了,加上-f参数即可。

1
2
3
4
5
6
7
8
9
10
11
$ ln -s b.log as.log
ln: failed to create symbolic link 'as.log': File exists

# 强制创建
$ ln -sf b.log as.log

$ ll
-rw-rw-r--. 1 user user 85716 Apr 5 22:16 a.log
-rw-rw-r--. 2 user user 85716 Apr 5 21:34 ah.log
lrwxrwxrwx. 1 user user 5 Apr 5 22:21 as.log -> b.log
-rw-rw-r--. 1 user user 85716 Apr 5 22:17 b.log

库函数和系统调用的区别

库函数是更高级别的,完全在用户空间里运行,并为程序员提供了更方便的做实际工作的函数接口。Higher level,run in user space,more convenient。

系统调用代表用户以内核模式工作,由操作系统本身的内核提供。In kernel mode。

库函数printf看上去类似于一般输出函数,但是它实际上只是格式化你提供给字符串的数据,并用低级系统调用write编写字符串数据,然后将数据发送到一个与终端的标准输出关联的文件中。

DiFX问题集锦

DiFX 使用中找不到fl

DiFX使用中遇到/usr/bin/ld can not find –fl

这个主要是因为安装DiFX时没有把安装包装全。

可以参考CentOS 安装DiFX

解决方法为安装flex*,全包(包括开发库)而不只是flex。

DiFX-HOPS出现的lpng12问题

在使用difx的install附加安装HOPS的时候,报错说是-lpng12没有找到,自己看了一下,丫的libpng我装了呀,使用yum search了一下,发现libpng还有libpng10、libpng12,囧。

解决方法很简单:

1
yum install libpng12*

当然,对于centos而言,如果找不到这个package,可以去http://fr2.rpmfind.net/linux/rpm2html/search.php?query=libpng12.so.0&submit=Search+…&system=centos&arch=进行下载,直接安装rpm包也是ok的。

unable to find rpm tool

在安装DiFX的时候出现这个问题。

运行install.sh出现:

ERROR: Unable to find rpm tool, please add its location to your PATH and restart installation
Installation failed.
Please see /var/log/ipp_em64t_install.log for details.

Installation is complete:
Thank you for using Intel Software Development Products, tools for improving application performance.

解决方法为: /install/install –nonrpm

这个bug在ipp5.3和ipp6.0都是存在的,从ipp6.1开始修复,对于全新的IPP,多个版本可以共存安装。

ImportError:No module named mx.dateTime

DiFX中getEOP.py问题

使用getEOP.py的时候出现

1
ImportError:No module named mx.dateTime

缺少mx包,解决方法使用yum install python-egenix-mx-base即可。

DiFX 使用中RPC无法使用的问题及解决方法

最新更新,直接执行startCalcServer即可解决这个问题了。

我记得去年貌似就碰到这个问题,不过只是不同的发行版而已,今天是Fedora 17,Pro.Z的机器。

问题就是difx的calcserver程序是需要调用rpc的,而大部分情况下,出错的原因是因为rpc支撑环境没有安装,其实如果使用了NFS,这个问题一般是没有问题的。

解决方法少许有些不同,不过还是可以只使用的:即安装portmap程序包,然后尝试service rpcbind start

1
2
$ apt-get install portmap
$ service rpcbind start

这里很高兴还记得ALT+F2,然后r重启X11 shell的技巧。

关于difx的troubleshooting也有提及RPC service unavailable

If an RPC error is encountered when starting the calcserver program, it is possible that the portmap service is either not installed or not running. Please consult your OS distribution documentation for rectifying this. In the case of Debian or Ubuntu Linux, the solution may be as simple as:

关于portmap端口映射

端口映射是一个服务器,将RPC程序号转换为DARPA的协议端口号。在使用RPC调用时它必须运行。

portmap进程的主要功能是把RPC程序号转化为Internet的端口号。

当一个RPC服务器启动时,会选择一个空闲的端口号并在上面监听(每次启动后的端口号各不相同),同时它作为一个可用的服务会在portmap进程注册。一个RPC服务器对应惟一一个RPC程序号,RPC服务器告诉portmap进程它在哪个端口号上监听连接请求和为哪个RPC程序号提供服务。经过这个过程,portmap进程就知道了每一个已注册的RPC服务器所用的Internet端口号,而且还知道哪个程序号在这个端口上是可用的。portmap进程维护着一张RPC程序号到Internet端口号之间的映射表,它的字段包括程序号、版本号、所用协议、端口号和服务名,portmap进程通过这张映射表来提供程序号-端口号之间的转化功能

如果portmap进程停止了运行或异常终止,那么该系统上的所有RPC服务器必须重新启动。首先停止NFS服务器上的所有NFS服务进程,然后启动portmap进程,再启动服务器上的NFS进程。

RPC

远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。

Linux RPM软件包

软件包比较通用的有两种,如下:

  • Redhat系列的rpm包
  • Debian系列的软件包格式dpkg,即deb包

可以使用工具alien(不是异形,^_^)来转换rpm包和deb包

RPM软件包的优点

  • 使用广泛
  • 允许你只用一条命令来安装软件
  • 只需要处理一个文件
  • RPM自动处理软件包之间的依赖性检查
  • RPM软件包被设计为由“最干净”的源代码而来从而允许你对它重新进行编译

创建RPM包

  • 收集需要打包的软件
  • 创建SPEC文件,该文件描述了如何建立软件包
  • 用rpmbuild命令创建软件包

  • indent : changes the appearance of a C program by inserting or deleting whitespace.能够按照预先定义好的或者自定义的标准调整源代码以及代码缩进的格式以达到所需要的风格;
  • etags, ctags – generate tag file for Emacs, vi。生成的文件能够增强编辑器浏览和分析源代码的风格;

语句

C语言中有很多的语句:空语句、表达式语句、代码块、if语句、while语句、break和continue语句、for语句、do语句、switch语句、switch中的break语句、default子句、goto语句。

基本上,C语言实现了其他现代高级语言所具有的所有语句。

if语句

在C的if语句和其他语言的if语句中,只存在一个差别:就是C不具备布尔类型,而是用整型来代替。

对于if-else配对的问题,else字句从属于最靠近它的不完整的if语句。

break和continue语句

在while语句中,使用break语句可以永久终止循环,而使用continue语句,用于永久终止当前的那次循环。这两条语句的任何一条如果出现于嵌套的循环内部,它只对最内层的循环起作用,你无法使用break或者continue语句影响外层循环的执行。

while语句的执行过程

有时while语句在表达式中就可以完成整个语句的任务,于是循环体就无事可做,此时单独用一行表示一条空语句是比较好的做法,比如:

1
2
while((ch = getchar() ) != EOF && ch != ‘\n’)
;

for语句

for语句的形式为:

1
2
for (expression1; expression2; expression3)
statement;

其中expression1称为初始化部分,expression2称为条件部分,expression3称为调整部分。
与上述for语句相同意义的while语句:

1
2
3
4
5
6
expression1;
while(expression2)
{
statement;
expression3;
}

从上面两个语句的对比,我们可以看出,for循环有一个风格上的优势,就是把所有用于操纵循环的表达式收集在一起,放在同一个地点,便于寻找。
do语句

   当你需要循环体至少执行一次时,选择do语句。

switch中的break语句

switch语句中的执行中遇到了break语句,执行流就会立即跳到语句列表的末尾。而break语句的实际效果是把语句列表划分为不同的不同,这样,switch语句就能够按照更为传统的方式工作。其实如果这样的话,那么最后一个语句就不用添加break了,但是还是加上了break,主要是在以后的维护中,如果维护人员添加代码而忘记了break就有可能影响程序的效果。
default子句

对于switch中的default语句,我一直认为要放在最后,但是测试了一下,发现default可以出现在任何一个case标签出现的地方而不仅仅是最后。

switch语句的执行过程

对于符合多个case的情况,最好写上注释,防止在检查的时候额外加上了break而导致出现bug。

goto语句

goto语句可以出现在函数中的任何一个位置,这种无序的跳转是很危险的,所以,如果有其他方法搞定,最好少用goto语句。

当然,针对跳转出多层嵌套,goto确实是一种比较方便的方法。当然可以使用一个标志值,来跳转出所有的循环,或者将所有的循环放在一个函数中,直接使用return来跳出。对于设置标志值,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum {EXIT,OK} status;

status = OK;
while(status == OK && condition1)
{
while(status == OK && condition2)
{
while(status == OK && condition3)
{
if(something wrong)
status = EXIT;
break;
}
}
}

总结

另外还需要注意:C并不具备任何的输入输出语句,IO是通过调用库函数实现的,C也不具备任何异常处理语句,它们也是通过调用库函数来完成的。

结构体无法比较

由于结构体的成员不一定是连续地存储在内存中,所以不能用运算符==或!=来对结构体进行比较,事实上,在一个结构体的存储区域内可能会出现一些“空洞”,这是由于计算机是按照一定的边界,例如半字、字、双字边界来存储不同数据类型的变量。

对结构体的访问

  • 结构体成员运算符structure member operator(.),也被称为圆点运算符
  • 结构体指针运算符structure pointer operator(->),也被称为箭头运算符

指针方式的结构体

在传递一个结构体时,用传地址的方式比采用传值的方式效率高,因为传值会要求复制整个结构体。

多重结构体变量访问

这里由引出来另一个比较有意思的问题,既然结构体的变量可以不同类型的,当然结构体也可以作为内部变量,如下所示,shao_struct_v2.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>

struct Date{
int year;
int month;
int day;
};

struct Student{
char id[5];
char name[10];
int age;
char sex[10];
struct Date date;
};

int main(int argc, char const *argv[])
{
struct Student s1 = {"0001", "Little Bob", 20, "male"};
strcpy(s1.name, "Big Bob");
s1.date.year = 1990;
s1.date.month = 1;
s1.date.day = 12;

printf("ID \t Name \t AGE \t\t SEX \t\n");
printf("%s\t%s\t%d(%d-%d-%d)\t%s\n",s1.id, s1.name, s1.age, s1.date.year, s1.date.month, s1.date.day, s1.sex);

return 0;
}

输出为

1
2
3
4
5
6
➜  struct git:(master) ✗ gcc shao_struct_in_struct.c
➜ struct git:(master) ✗ ls
a.out shao_struct_in_struct.c shao_struct_simple.c
➜ struct git:(master) ✗ ./a.out
ID Name AGE SEX
0001 Big Bob 20(1990-1-12) male

根据“用户输入”初始化结构体

用户输入信息需要访问到结构体变量所在的内存空间地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Student
{
char id[5];
char name[10];
int age;
char sex[3];
};

int main()
{
struct Student s1;
printf("input id:>");
scanf("%s",s1.id);
printf("input age:>");
scanf("%d",&s1.age);
}
​```

## 定义结构体类型数组,通过数组同时初始化多个结构体

​```c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
char id[5];
char name[10];
int age;
char sex[3];
};
void main()
{
struct Student S[2]={{"0001","Newton",35,"男"},
​ {"0002","Lagrange",30,"男"}}; //通过数组同时初始化多个结构体
for(int i=0;i<2;++i)
​ {
printf("id=%s,name=%s,age=%d,sex=%s\n",
​ S[i].id,S[i].name,S[i].age,S[i].sex);
​ }
}

定义结构体指针,通过指针指向符->访问结构体成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
char id[5];
char name[10];
int age;
char sex[3];
};

void main()
{
int a =10;
int *pa=&a;
​ Student s1={"0001","Euler",32,"男"};
printf("id=%s,name=%s,age=%d,sex=%s\n",s1.id,s1.name,s1.age,s1.sex);

struct Student *ps=&s1; //指向结构体的“结构体类型指针”
printf("id=%s,name=%s,age=%d,sex=%s\n",ps->id,ps->name,ps->age,ps->sex);
//通过指针指向符->访问结构体成员变量
}

线性链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#define ElemType int
struct Node
{
​ ElemType data;
struct Node *next;
};

typedef Node* List;

void InitList(List *head)
{
​ *head=NULL;
}

void CreateList(List *head)
{
​ *head=(Node *)malloc(sizeof(Node));
​ (*head)->data=1;
​ (*head)->next=NULL;

Node *p=*head;
for(int i=2;i<=10;++i)
{
Node *s=(Node *)malloc(sizeof(Node));
s->data=i;
s->next=NULL;

p->next=s;
p=s;
}
}

void ShowList(List head)
{
​ Node *p=head;
while(p!=NULL)
​ {
printf("%d-->",p->data);
​ p=p->next;
​ }
printf("Over!\n");
}

void main()
{
​ List mylist;
​ InitList(&mylist);
​ CreateList(&mylist);
​ ShowList(mylist);
}