C笔记(系统编程)

来源:互联网 发布:人工智能研究的难点 编辑:程序博客网 时间:2024/05/16 04:40

bss段放未赋值全局变量。只有栈和堆在程序运行时才有数据,其他数据段生成a.out文件就已经有数据,可以用size a.out查看。所以在在一个程序里如果创建一个进程,而直接加载程序,那么加载来的程序(调用execve函数)会覆盖上一个程序的代码段,只读段,等除栈堆以外的段。那么调用它的那个程序的代码段,数据段已经不存在,不可能再运行这个程序。所以for()创建子进程时,是将父进程所有的段都复制到子进程开辟的4G空间里,这个复制过程是执行到for()内部时执行,所以for()执行一半时会出现父,子进程,fork()结束时,父,子进程各返回一个值,所以有两个pid,父进程得到的是子进程的pid,而子进程返回值是0,这么样出现两个进程。但是些时父,子进程的代码一样,如果上加载新的程序来,代码保持不变
只读段放的是常量。
C语言折行。在行末加上双引号,下一行的开头也加上双引号即可,可斜杠也可以,
C标准库里main函数的原型只有两个,但linux下支持int main(int argc, char *argv[], char *env[]),这个原型只能在linux下运行,所以移植性不好。
snprintf(char *dest,size,format,char *scr)格式化输入。
snprintf(buf,sizeof(buf), %s%s, str1, str2);将字符串str1与str2连接在一起。
sprintf(char *dest,format, *scr)格式化输入。
fgets(FILE file) 读取文件的一行。
atoi(char *p);自动将p指向的字符转为整型,如果p指向的字符不是0到9,刚会自动结束,因此不需要人为判断。
函数返回值是指针时,返回的指针指向有三种可能:全局变量,malloc分配的地址,局部变量地址,要注意区分。若为全局再次写入前,要把前一次读到的数据保存,否则会被覆盖。
子函数中返回值是指针的,指针所指向的地址应该是通过内存分配得到,或是通过参数传入函数,不能在函数内定义一个指针变量,因为函数退出时,它的栈会被销毁,指针所指向的地方数据已经被销毁,再通过指针来访问会出现段出错的错误。
du -sh 查看文件夹(文件块)的大小,而ll(ls)查看的是文件系统的大小,并不一定是文件实实在在在硬盘的大小。(空洞文件)
man 的第一章基本命令,第二章是系统调用,第三章是标准库的函数
内核是一个应用程序,它是给其他应用程序提供运行的环境;
进程管理:让两个应用程序同时运行。为了防止多个应用程序时间访问同一个物理内存,所以为每一个应用程序分配4G的虚拟内存,最后才将这些虚拟内存映射到物理内存。

操作系统架构:
upp
---------------
shell|clib,lib|app
---------------
API
---------------
Kernel(驱动,进程,内存,文件,网络)
--------------
bootloader
---------------
硬件
posix  操作系统API函数接口标准。 sysv SBD 是发行版本。

文件操作:
r     只读
r+   可读可写
w     只写,文件不存在会创建,文件会被清空再写入
w+   具有w所有功能,且可读
a     追加,文件不存在会追加
a+   比a多了追加功能。
fread/fwrite 按字节数操作,与字符,行数都无关。
常用fgets,fprintf,snprintf

系统编程函数返回值是int型的,返回值为-1,则出错,若为指针出错便返回NULL
fopen是库函数,它是封闭了open而得到,而open是内核的API函数。

文件描述符是当时进程最可用的文件描述符但0 1 2 是系统已经占用的文件描述符
0   标准输入
1   标准输出
2   错误输出
stdin   文件输入流指针FILE 型
stdout  文件输出流指针
stderr  文件错误输出流指针

fopen有缓冲区,open没有缓冲区
fflush(fd); 用于刷新缓冲区。
缓冲区在写零碎内容时才使用,大文件直接用没有“f“的函数。若写的内容大于缓冲区大小,则将内容直接写入文件,而不会将内容缓冲区,这时是不经过缓冲的。默认缓冲区的大小为8K(由宏BUFSIZE定义)。

setvbuf(fd,*buf,model,size);用于设置自己的缓冲区。

系统调用很消耗资源,尽量少用

crypt(passwd, password );函数是将输入的密码与已经加密后生成的密码的密码生成一个输入密码加密后的密码,以便用于比较,看密码是否匹配,编译时要链接库。

时间函数
time();
localetime();
ctime();
asctime();
strftime();格式化输出时间。





dup()函数,复制文件描述符。int fd = dum(1);对fd操作,相当于对标准输出操作。dup2(oldfd,newfd);将旧的文件描述符重新定义为新的文件描述符。dup2(1,100),write(100,"adafla",10);文件描述符100成为标准输出。

fcntl(),可以获取打开的文件的标志位,
flag = fcntl(0,F_GETFL);获取文件描述符
fcntl(0,F_SETFL,flag | O_NONBLOCK);取消特殊设备文件(块设备)的阻塞。
ioctl()只能对设备文件操作。

用open("path",flags,model)创建一个文件,后面的参数 model是八进制,所以设置时数字前要加0,如0777,0755。前面的0不可少。
用户的配置文件在/etc/passwd下
ln -s 链接文件,创建链接文件,

chdir(),只改变当前(函数内部)目录,不会改变终端的命令。

--------------------------------------------
进程
-------------------------------------------
setenv()改变的是环境变量(命令env),它影响其子进程,而不会改变真正的工作路径,
而getpwd()获取的是真正的工作路径。

getuid() 获取当前登陆用户ID
geteuid() 获取有效用户ID。这两个函数只有文件加了特权位才不一样,否则获得的都是当前用户ID。
只有root用户可以执行setuid();seteuid();即只有getuid() == 0 是才可以执行以上两个函数。
execve(path,*argv[],*env);其中argv[0]是进程名,可以随意命令,若是不传,则默认的是程序名(path);
ps -aux |grep keyword   按关键字查看进程。
可执行程序加载到内存,运行起来便是进程


exit(0);在函数退出时才去执行注册的函数(指针函数)。

exec族函数:
    execl   给可执行程序传的参数以指针
        v
        e
        p

/*
     *execl("./test","kyo", "aaaa", "bbbb", "45444",NULL);
     *execlp("ls","kyo", "-l", NULL);
     */

        /*
         *v   给可执行程序传的参数以指针数组形式传进去
         *l   给可执行程序传的参数以可变参形式传进去
         *e   可以传自定义环境变量
         *p   可以到PATH环境查询可执行文件
         */
       {
    char *argv[] = {"kyo","bbbb", "cccc", NULL};
        char *env[] ={"PATH=/bin", "AA=BB", NULL};

        execve("./test", argv,env);
        perror("execve");
       }
僵尸进程会占用资源(如PID),要以免其出现。父进程退出后,其子进程如果是僵尸进程,也会跟着退出。父进程,不等待,而子进程先退出,则会出现僵尸进程。父进程会在wait(),处等待子进程退出,而wait()以前的语句是并发的。当父进程产生多个子进程,只要一个子进程结束,wait()便会结束,所以创建了多少个子进程,就得在父进程里有多少个wait函数。
父进程回收子进程资源包括pid,子进程退出状态,exit的返回值。
exit(data);用exit退出反回一个32位的数,其中返回值只有8到16位,所以其返回值范围是0到255。返回值是进程ID,id =wait(&ret); *ret的是但exit的data,id 则是子进程ID。

若父进程先退出,子进程变成孤儿进程,此时的子进程ppid为1,inti()的进程id为1。孤儿进程是允许的,而僵尸进程是不允许的。


su - username,加了-是完全切换,会把环境变量里的值一起改变,环境变量PATH是存放的是可执行文件路径。


initgroups();setgid();seguid();这是三个有函数顺序不能换,最后才能改变uid,只有root用户才能执行上面三个函数。
su,切换用户的命令,需要有特权位,文件加了特权位(chmod u+s file),有些操作必须用root用户做,所以相应的可执行文件要加特权位。