#include<stdio.h>
#include<string.h>
int main()
{
FILE * handle;
char con[100];
//第一种使用fopen的方式,windows系统是直接输入文件的绝对路径需要这种方式"e:\\aaa.txt",注意是两个反斜杠,一个反斜杠的话就错了
//handle=fopen("e:\aaa.txt","r");
//第二种使用fopen的方式,利用一个字符串来保存文件路径和名字,运行程序后,在dos下提示你输入路径名字,可以输入"e:\\aaa.txt",
//或者"e:\aaa.txt",也就是说dos下一个反斜杠或者两个反斜杠都是正确的
//char buf[80];
//printf("please input the filename you want to open:");
//gets(buf);
//handle=fopen(buf,"r");
//利用一个初始化好的字符串也可以正确的使用fopen,以下这几种初始化方式都是正确的都是两个反斜杠
//char buf[]="e:\\aaa.txt";const char buf[100]="e:\\aaa.txt";
char *buf="e:\\aaa.txt";
handle=fopen(buf,"r");
if(!handle)
perror("can not open this file\n");
else
printf("you have opened this file successfully!\n");
fgets(con,100,handle);
printf("the content of file is:%s\n",con);
fclose(handle);
return 0;
}
主要介绍了fopen函数的第一个参数的使用,代码里面说的已经很清楚了,其余类似fopen的函数的使用也一样
摘要: linux文件权限的说明,和chmod命令的使用
阅读全文
关于PATH的作用:
PATH说简单点就是一个字符串变量,当输入命令的时候LINUX会去查找PATH里面记录的路径。比如在根目录/下可以输入命令ls,在/usr目录下也可以输入ls,但其实ls这个命令根本不在这个两个目录下,事实上当你输入命令的时候LINUX会去/bin,/usr/bin,/sbin等目录下面去找你此时输入的命令,而PATH的值恰恰就是/bin:/sbin:/usr/bin:……。其中的冒号使目录与目录之间隔开。
关于新增自定义路径:
现在假设你新安装了一个命令在/usr/locar/new/bin下面,而你又想像ls一样在任何地方都使用这个命令,你就需要修改环境变量PATH了,准确的说就是给PATH增加一个值/usr/locar/new/bin。你只需要一行bash命令export PATH=$PATH:/usr/locar/new/bin。这条命令的意思太清楚不过了,使PATH自增:/usr/locar/new/bin,既PATH=PATH+":/usr/locar/new/bin";通常的做法是把这行bash命令写到/root/.bashrc的末尾,然后当你重新登陆LINUX的时候(应该是linux启动时就会执行这个文件),新的默认路径就添加进去了。当然这里你直接用source /root/.bashrc执行这个文件重新登陆了。你可以用echo $PATH命令查看PATH的值。
关于删除自定义路径:
当某天你发现你新增的路径/usr/locar/new/bin已经没用了的话,你可以修改/root/.bashrc文件里面你新增的路径。或者你可以修改/etc/profile文件删除你不需要的路径.
一般来说,配置交叉编译工具链的时候需要指定编译工具的路径,此时就需要设置环境变量。例如我的mips-linux-gcc编译器在“/opt/au1200_rm/build_tools/bin”目录下,build_tools就是我的编译工具,则有如下三种方法来设置环境变量:
--------------------------------------------
临时环境变量(重启后消失)
-----------------------------------------------------
1、直接用export命令:
#export PATH=$PATH:/opt/au1200_rm/build_tools/bin
查看是否已经设好,可用命令export查看:
[root@localhost bin]# export
declare -x BASH_ENV="/root/.bashrc"
declare -x G_BROKEN_FILENAMES="1"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="localhost.localdomain"
declare -x INPUTRC="/etc/inputrc"
declare -x LANG="zh_CN.GB18030"
declare -x LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
declare -x LESSOPEN="|/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="root"
declare -x LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"
declare -x MAIL="/var/spool/mail/root"
declare -x OLDPWD="/opt/au1200_rm/build_tools"
declare -x PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin:/opt/au1200_rm/build_tools/bin"
declare -x PWD="/opt/au1200_rm/build_tools/bin"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_ASKPASS="/usr/libexec/openssh/gnome-ssh-askpass"
declare -x SSH_AUTH_SOCK="/tmp/ssh-XX3LKWhz/agent.4242"
declare -x SSH_CLIENT="10.3.37.152 2236 22"
declare -x SSH_CONNECTION="10.3.37.152 2236 10.3.37.186 22"
declare -x SSH_TTY="/dev/pts/2"
declare -x TERM="linux"
declare -x USER="root"
declare -x USERNAME="root"
可以看到,环境变量已经设好,PATH里面已经有了我要加的编译器的路径。
里去操作了。
永久环境变量
--------------------------------------------------------
2、修改profile文件:
所有用户(不安全)
修 改/etc/profile(对所有用户都是有效的)
#vi /etc/profile
在里面加入:
export PATH="$PATH:/opt/au1200_rm/build_tools/bin"
3. 修改.bashrc文件:
# vi /~/.bashrc
(单独用户)
修改~/.bashrc文件。 htt(74)p://www.icwin.net/bbs http://www.wantso.com (每个用户目录下都有,ls -all)
cd ~
vi .bashrc
在里面加入:
export PATH="$PATH:/opt/au1200_rm/build_tools/bin"
后两种方法一般需要重新注销系统才能生效,最后可以通过echo命令测试一下:
# echo $PATH
看看输出里面是不是已经有了/my_new_path这个路径了。
-----------------------------------------------------------------------------------------------------------------------
“/bin”、“/sbin”、“/usr/bin”、“/usr/sbin”、“/usr/local/bin”等路径已经在系统环境变量中了,如果可执行文件在这几个标准位置,在终端命令行输入该软件可执行文件的文件名和参数(如果需要参数),回车即可。
如果不在标准位置,文件名前面需要加上完整的路径。不过每次都这样跑就太麻烦了,一个“一劳永逸”的办法是把这个路径加入环境变量。命令 “PATH=$PATH:路径”可以把这个路径加入环境变量,但是退出这个命令行就失效了。要想永久生效,需要把这行添加到环境变量文件里。有两个文件可选:“/etc/profile”和用户主目录下的“.bash_profile”,“/etc/profile”对系统里所有用户都有效,用户主目录下的“.bash_profile”只对这个用户有效。
“PATH=$PATH:路径1:路径2:...:路径n”,意思是可执行文件的路径包括原先设定的路径,也包括从“路径1”到“路径n”的所有路径。当用户输入一个一串字符并按回车后,shell会依次在这些路径里找对应的可执行文件并交给系统核心执行。那个“$PATH”表示原先设定的路径仍然有效,注意不要漏掉。某些软件可能还有“PATH”以外类型的环境变量需要添加,但方法与此相同,并且也需要注意“$”。
注意,与DOS/Window不同,UNIX类系统环境变量中路径名用冒号分隔,不是分号。另外,软件越装越多,环境变量越添越多,为了避免造成混乱,建议所有语句都添加在文件结尾,按软件的安装顺序添加。
格式如下():
# 软件名-版本号
PATH=$PATH:路径1:路径2:...:路径n
其他环境变量=$其他环境变量:...
在“profile”和“.bash_profile”中,“#”是注释符号,写在这里除了视觉分隔外没有任何效果。
设置完毕,注销并重新登录,设置就生效了。如果不注销,直接在shell里执行这些语句,也能生效,但是作用范围只限于执行了这些语句的shell。
相关的环境变量生效后,就不必老跑到软件的可执行文件目录
条件编译,有三种格式
1 #if 表达式
程序段1
#else
程序段2
#endif
很简单,表达式为真编译1,否则编译2。
2 #ifdef 标识符
程序段1
#else
程序段2
#endif
如果标识符已用#define定义过,则为真编译1,否则编译2
3 和2的基本一致就是把ifdef换成ifndef。用法是为假编译1,否则2
比如#include <stdio.h>
int main()
{
#ifdef _DEBUG
printf("hello world\n");
#else
printf("no debug");
#endif
return 0;
}
在linux用gcc编译是,如果使用gcc -D_DEBUG -o main main.c。则就是说明定义过_DEBUG,运行结果是hello world。注意是-D选项,-D后面紧跟着标识符名字
如果使用:gcc -o main mian.c,怎说明没有定义标识符,运行结果是no debug了。
当然,也可以直接再代码里显示写上一句:#define _DEBUG,也能有相同效果。
宏的使用的核心,就是替换,换是最关键的。
1、不带参数的宏定义
这是最简单的了,比如#define PI 3.1415926
预编译的时候,把代码中的PI替换就行了。一般情况下宏名用大写字母,不要在行末加分号。
2、带参数的宏定义
不只是进行宏体的替换,还要进行参数的替换。
比如:#define MAX(x,y) (x>y)?x:y
宏展开的时候要将语句中宏名后面的括号内的实参代替形参。另外为了避免发生错误,凡是带运算符的参数要用圆括号括起来。
3、不常见但是很重要的用法
(1)#define FUN(a) "a"
那么当输入FUN(345)是,照样会被替换成“a”,无论宏的实参是什么,都不会影响其被替换成"a"的命运。
也就是说,""内的字符不被当成形参,即使它和一模一样。
(2)有参宏定义中#的用法
#define STR(str) #str
str前面的那个#用于把宏定义中的参数两端加上字符串的""
比如代码中有STR(my#name),那么在展开的时候被替换成"my#name"。
一般由任意字符都可以做形参,但以下情况会出错:
STR())这样,编译器不会把“)”当成STR()的参数。
STR(,)同上,编译器不会把“,”当成STR的参数。
STR(A,B)如果实参过多,则编译器会把多余的参数舍去。(VC++2008为例)
STR((A,B))会被解读为实参为:(A,B),而不是被解读为两个实参,第一个是(A第二个是B)。
(3) 有参宏定义中##的用法
#define WIDE(str) L##str
则会将形参str的前面加上L
比如:WIDE("abc")就会被替换成L"abc"
如果有#define FUN(a,b) vo##a##b()
那么FUN(id ma,in)会被替换成void main()
再比如:
#define s5(a) supper_ ## a
#include <stdio.h>
void supper_printf(const char* p )
{
printf("this is supper printf:\n%s\n",a);
}
int main()
{
s5(printf)("hello owrld");//就是调用函数supper_printf.
return 0;
}
(4) 多行宏定义:
#define doit(m,n) for(int i=0;i<(n);++i)\
{\
m+=i;\
}
关键是要在每一个换行的时候加上一个 "\ " ,最后一行不用加。这样使用的时候就可以用doit(m,n)来代替for循环结构了。
还是先看看csapp上的解释:并发(concurrency)是指一个通用上的概念,指一个同时具有多个活动的系统;并行(parallelism)指的是用并发使一个系统运行得更快。
百度的解释:并发, 在
操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个
处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。也就是实际上,并发使指的在逻辑上,宏观上,一个计算机能够同时执行多个任务多个程序,但是微观上看,在同一个时刻,只有一个程序在运行,但是由于处理器速度非常快的在几个程序来回切换,让我们觉得是好几个程序同时在执行。
而并行则是真正的让计算机在物理上同时执行多个活动。
举个例子,妈妈(cpu)在上午10点后开始做家务(程序),首先是收拾房间,收拾完房间后,开始洗衣服,洗完衣服后开始做午饭,那么到中午12点,妈妈一共做了3件事情(程序),从宏观上看,妈妈在一个上午的时间同时做了3个家务,但是实际上这三件事并不是同时做的。而如果妈妈这么选择做家务:在收拾房间的同时,把衣服扔到洗衣机里让洗衣机洗着,同时又让电饭锅蒸着米饭,等妈妈收拾完房间的同时衣服也洗好了,饭也做熟了。三件事情等于是真正上的同时执行的,这就是并行。很明显我们会发现,并行的速度要远远快于并发。
当然并发和并行的具体实现远远很复杂,这只是先从概念上区分开并发和并行。
先写出将要解释的哪几对概念:
程序、进程和线程
并发和并行
多线程和超线程
单核和多核。(
必须先咒骂一句,以下内容其实是第二遍写了,在第一次发表的时候,没有发表成功,结果全都没有了,还得重新写一遍,第一次写的内容其实很多,第二次是在没有心思写太多了,只写主要的了,TMD....)
程序是死的,只是安装到你的电脑上的一堆文件而已,你不允许它,它就静静躺在那里,什么都不做。进程:很专业的解释是,操作系统对一个运行的程序的一种抽象(CSAPP)。果然是很抽象的,抽象的基本不懂。进程就是代表程序在电脑里运行的,每一个程序至少有一个进程,进程是进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。当赋予死的程序以生命时,它就成了一个活动的实体,称之为进程。每一个进程运行后,都会向cpu索要相应的系统资源,都会有自己一定的地址空间,在这空间里会存放文本区域(text region)、数据区域(data region)和
堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。线程,线程,有时被称为
轻量级进程(Lightweight Process,LWP),是程序执行流的最小
单元。每一个进程都至少有一个主线程,进程向系统申请一段地址空间,而线程并不拥有专属于自己的地址空间,每个线程都只拥有一点点必不可少的资源,进程中所有的线程共享进程的资源。线程一个创建和撤销另外一个线程。线程其实才是真正利用cpu的单位,它是能独立运行的基本单位,也是独立调度和分派的单位。可以这么认为,进程向cpu申请了地址空间后,然后把真正要做的工作全部交给了线程去做,但是线程使用的资源是由进程代表申请的。
拿一个c程序举例子来说明下进程和线程的关系,一个c程序只有一个主函数,main函数,但是可以拥有其他很多子函数,main函数是c程序运行的切入点,通过main函数可以调用其他子函数,main函数和其他子函数共享全局变量,也可以相互之间很方便的传递数据。这里,可以把进程看成一个c程序,一个进程也只拥有一个主线程,主线程就是相当于main函数,线程之间共享数据,也可以相互很方便的传递数据。
再举一个更生动的数据。说:
一堆肉,是死的,什么都做不了,但是一堆肉组成了一个人,人是活的有生命的,人又由很多器官组成,当人想要做什么事情的时候,其实是由大脑这个器官调配其余器官来真正做的。可以说人在这个社会上占有一定的资源,但是真正使用这些资源的是器官,但是我们不能说器官占有这些资源。这里,程序就是一堆肉,进程就是一个人,线程就是器官,其中主线程是大脑。
这些概念都有所了解,但是要想完全说清楚很难了,等我逐一弄懂,并且确定自己的了解是正确的后,我会贴出来的。
WAITING...
首先看名字不要太多误会,我说的意思是不要看《深入理解计算机系统》(裘奕利雷迎春翻译),但是《computer system a programmer‘s perspective》这本书是一定要看的。
有人说这两本书不是一样嘛,一个英文原版一个中文翻译版。
非也!
当初自恃英文水平不是很高,不敢看英文原版的,于是乎买了本中文版。看这本书也有段时间了,现在是越看越窝火,翻译的真的真的是太差劲了。
先从翻译的这个中文破名字说起,英文名字直接翻译汉语大概应该是:以一个程序员的角度来看计算机系统。不知道怎么就给翻译成了深入理解计算机系统。我想百分之90的人们看到这个名字,都不会联系到实际的书的内容。
翻开书正文内容第一页——出版者的话,第六个字就很明显的错了,也不知道是翻译的错误或者说是作者语文水平太差或者说是印刷错误(这个错误还勉强可以接受吧),由此管中窥豹,可见翻译者或者出版社的态度了,至少不是十分认真了,书的仅仅第六个字就弄错了。
再谈,书的内容的翻译,我想如果要是季羡林大师再世的话,仅从汉语的角度看看这本中文书(虽然我可以基本肯定大师不太懂计算机系统和c吧),非得气死。从我一个工科学生对语文的了解,就可以发现通篇的汉语语法错误,不是缺主谓宾就是缺定状补,有的错误凭着多年对汉语的应用可以自己理解过来,但是通篇很多的错误实在让人受不了,还有更过分的是对一些专业术语的翻译,从汉语表面的意思实在联想不到和这个术语的实际意义有啥相关系。再有就是很多很多的超长句子,一个句子有太多的修辞词定语状语,我说你丫的翻译者就不能把长句分成几个短句啊!
本来有些内容就不是很好理解,很晦涩,再加上这个糟糕的翻译,在想深入理解书中的内容时,真是太痛苦了!我真有一种想痛骂的冲动!!
以后再买一些英文技术书籍时,坚决只买英文版的,虽然开始看时会慢些,需要对着个英文翻译软件查不认识的单词,但后期肯定会越来越好的。
强烈建议大家学这书的内容时,买英文版的,至少不要买这一版的中文版!!
另外再点名另外一本中文翻译的书《数据结构和算法分析:C++描述》,翻译的更差劲!
点名表扬一本书《C++ primer》,这本书的中文翻译我自认为在我看到的众多翻译过来的书中是最好的了!
第一遍看这本书的时候,稍微扫了一遍这个内容,当时看起来有时生硬,不是很懂,等于跳了过去了。现在再看,感觉很有用,也基本能看明白了。说个题外话,有时候看有些内容,第一次看到的时候,觉得很难理解很难理解,就是反复看好几遍也理解不了。那么不妨就放下这段内容,也许你学过后面的内容的后,有天你再返回来看当初不懂的,就豁然开朗了,学习这本c++primer的过程中,真的有太多的这种体会了。
开始正题:
#define 指示的接受后面的名字,并把这个名字定义为预处理器变量,常用大写。
#ifndef 字面意思就是if not define 如果没有定义。就是如果后面的名字没有被定义成预处理器变量,那么这句话后所有的程序都将被执行,直到遇见#endif
说明具体用法和意义。
假如我自己写了两个头文件one.h,和two.h。其中one.h包括的是一个类的定义;two.h由于也要用到这个类,所以这个头文件里面必然要有一行程序:#include“one.h”。
而我们的主程序里面,开始必然要把我们自己定义的头文件给加进去,必然应该有两行程序:#include“one.h”和#include“two.h”,这样实际上one.h这个头文件被包含了两次,那个类的也相当于定义了两次,必然编译时会出现错误,为了解决这个问题。在one.h里应该加入这么一段程序:
#ifndef ONE
#define ONE
//这里应是one.h里面本来应该有的代码程序
#endif
这样这个头文件在主程序处理时只会被处理一次。因为:当主程序首先碰到这句::#include“one.h,时,由于是第一次处理one头文件,ONE这个预处理器变量还没有定义呢,所以会执行#define ONE这个语句,ONE变量被定义了,头文件one中的代码也会被执行了。当主程序碰到这句:#include“two.h”,由于two头文件中,也有这么一句:#include“one.h”,然后程序就会再次进入到one这个头文件中执行,这是由于ONE这个变量在第一次执行one这个头文件时已经被定义了,所以#ifndef ONE判断失败,不会执行后续的代码了,也就不会在执行one头文件中实际有用的代码了。这样保证了头文件只会被处理一次。
因此应该在自己编写的每个头文件中都加上保护符,避免头文件被多次包含。