一些LinuxC的小知识点(二)
一、read系统调用
系统调用read的作用是:从与文件描述符filedes相关联的文件里读入nbytes个字节的数据,并把它们放到数据区buf中。它返回实际读入的字节数。这可能会小于请求的字节数。如果read调用返回0,就表述未读入任何数据,已经达到了文件尾。同样,如果返回的是-1,就表示read调用出现了错误。
#include <unistd> size_t read(int filedes,void *buf,size_t nbytes);
二、普通文件(file)和设备文件(device)的区别
普通文件,即常用的磁盘文件由字节组成,磁盘文件中的字节数就是文件大小。而设备文件是链接,不是容器。键盘和鼠标不存储点击数:)设备文件的i节点存储 的是指向内核的子程序的指针,而不是文件的大小和存储列表。内核中传输设备数据的子程序被称为设备驱动程序。
三、在代码中控制控制台颜色
为了更方便地一眼看出程序输出的信息,很多时候我们都想要用颜色让输出的结果更为直观,无奈Linux下的颜色永远都是黑底绿字。其实改变颜色的方式很简单。如下代码所示
#include <stdio.h> #include <stdlib.h> #include "include/consoleColor.h" int main(int argc, char *argv[]) { printf(color_Red);//红色 printf("Hello, world!\n"); printf(color_Green);//恢复成默认的绿色 return EXIT_SUCCESS; }
输出的效果:
需要include的头文件
#ifndef __CONSOLE_COLOR__ #define __CONSOLE_COLOR__ char * color_Black= "\x1b[01;30m"; char * color_Red= "\x1b[01;31m"; char * color_Green= "\x1b[01;32m"; char * color_Yellow= "\x1b[01;33m"; char * color_Blue= "\x1b[01;34m"; char * color_PurplishRed= "\x1b[01;35m"; char * color_Cyan= "\x1b[01;36m"; char * color_white= "\x1b[01;37m"; #endif
相关阅读:让你的linux虚拟终端五彩缤纷(1)——LS颜色设置
四、多线程程序makefile编写的注意事项
对于多线程makefile中,要注意添加-lpthread,以便添加pthread的链接库。另外,需要加入宏定义-D_REENTRANT,以便将有的不可充入的函数或者变量,变成可重入的,以便适应多线程的要求(详见图1)。
下面是一个多线程的makefile。其中在ihome_arm.c这个文件中,我们用到了多线程。在ihome_arm.c中我们需要引用comtest.c中的函数。
ihome_arm : comtest.o ihome_arm.o
arm
-linux-gcc -o ihome_arm comtest.o ihome_arm.o -L/usr/include/nptl -
lpthread
all: pthread
comtest.o : comtest.c
arm
-linux-gcc -
c comtest.c
ihome_arm.o : ihome_arm.c comtest.c
arm
-linux-gcc -D_REENTRANT -I/usr/include/nptl -
c ihome_arm.c
clean :
rm ihome_arm comtest.o ihome_arm.o值得注意的是:在上面代码段中灰色背景下的语句前都要添加一个tab分隔符,必须是tab分隔符,不然就会报“Makefile:3:***遗漏分隔符。停止 。”。因为makefile中规定,如果是bash语句,那么必须在语句的最前用tab作分隔符。其中关于
-L/usr/include/nptl 的说明见图2.
图2 为什么添加-L/usr/include/nptl
以上图片来自《Linux程序设计 第四版》
五、头文件和源文件引用的注意事项
在知识点四中,我们程序里面有comtest.c、comtest.h、ihome_arm.c。其中在ihome_arm.c这个文件中,我们用到了多线程。在ihome_arm.c中我们需要引用comtest.c中的函数。我曾很傻气地直接在ihome_arm.c中直接引用comtest.c,结果导致大量的重复定义出现。正确的方式应该是,为ihome_arm.c引用的类型、变量、函数写一个comtest.h的头文件,这样就不会引起大量的重复定义。头文件编写的注意事项见上一篇文章。
六、Linux的sleep()和usleep()的使用和区别
1、sleep函数
函数名: sleep
头文件: #include <windows.h> // 在VC中使用带上头文件
#include <unistd.h> // 在gcc编译器中,使用的头文件因gcc版本的不同而不同
功 能 : 执行挂起指定的秒数
语 法 : unsigned sleep(unsigned seconds);
示例:
#include <unist.h> #include<stdio.h> int main() { int a; a=1; printf("hello"); sleep(a); printf("world"); return 0; }
2、usleep函数
函数名: usleep
头文件: #include <unistd.h>
功 能: usleep功能把进程挂起一段时间, 单位是微秒(百万分之一秒);
语 法: void usleep(int micro_seconds);
返回值: 无
内容说明:本函数可暂时使程序停止执行。参数 micro_seconds 为要暂停的微秒数(us)。
注 意:
这个函数不能工作在windows 操作系统中。用在Linux的测试环境下面。
参 见:usleep() 与sleep()类似,用于延迟挂起进程。进程被挂起放到reday queue。一般情况下,延迟时间数量级是秒的时候,尽可能使用sleep()函数。如果延迟时间为几十毫秒(1ms = 1000us),或者更小,尽可能使用usleep()函数。这样才能最佳的利用CPU时间。
七、时钟换算:
微秒,时间单位,符号us(英语:microsecond ).
1微秒等于百万分之一秒(10的负6 次方秒)
0.000 001 微秒 = 1皮秒
0.001 微秒 = 1纳秒
1,000 微秒 = 1毫秒
1,000,000 微秒 = 1秒
1s = 1000ms
1ms = 1000μs
1μs = 1000ns
1ns = 1000ps
1秒(s) = 1000 毫秒(ms) = 1,000,000 微秒(μs) = 1,000,000,000 纳秒(ns) = 1,000,000,000,000 皮秒(ps)
八、利用man查找制定C语言函数
man 3 函数
其中3代表man要查找的是C库函数。参考链接
九、多线程编程中主线程等待子进程结束
#include <stdio.h> #include <stdlib.h> #include <pthread.h> //省略了必要的函数 int main ( int argc, char **argv ) { struct MainArgus mMainArgus; mMainArgus.argc=argc; mMainArgus.argv=argv; int res;//用来判断线程是否创建成功,是否退出的标志 pthread_t a_thread; void *thread_result; res = pthread_create ( &a_thread,NULL,uart_pthread, ( void * ) ( &mMainArgus ) ); if ( res!=0 ) { exit ( EXIT_FAILURE ); } res=pthread_join ( a_thread,&
thread_result ); if ( res!=0 ) { exit ( EXIT_FAILURE ); } return EXIT_SUCCESS; }
在代码段中的灰色背景代码中,这句话关系到子线程a_thread能不能正常地运行完,pthread_join让main所在的主线程等待a_thread线程结束,才继续从pthread_join语句中往下执行。如果没有这一句,当子线程是比较耗时的操作,它在主线程运行到return EXIT_SUCCESS;的时候还没有结束的话,那么随着main所在的主线程的退出,子线程a_thread也将退出,也就是a_thread不能被正确地执行完,而是意外地退出了。
我们给pthread_join传递了两个参数,一个正在等待器结束的线程的标识符athread,另一个是指向线程返回值的指针。这个函数将等到它所指定的线程终止后才返回。然后main函数在pthread_join行之后,继续执行。
十、errno的由来
errno定义在头文件<errno,h>中,他是一个整形的变量。当系统调用和其他库函数发送错误的时候,errno用来标识错误是什么。
常用的用来报告错误的函数。它们是strerror和perror。
1、strerror用来将错误代码errno映射成一个字符串,该字符串对发生的错误类型进行说明。
函数原型如下
#include <string.h> char *strerror(int errnum); char *strerror_r(int errnum, char *buf, size_t buflen);
2、perror用来把errno变量中报告的当前错误映射到一个字符串,并把它输出到标准错误输出流。该字符串的前面先加上字符串s(如果不为空)中给出的信息,在加上一个冒号和一个空格。
函数原型如下
#include <stdio.h> void perror(const char *s);
3、一个小样例。在下面的这个例子中,我们错误地打开一个不存在的文件,产生一个errno,并用strerror和perror进行报告。
#include <stdio.h> //为了使用perror #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> //为了使用errno #include <string.h>//为了使用strerror int main ( int argc, char *argv[] ) { int CommFd = open ( "/dev/kkk", O_RDWR, 0 );//这里故意打开一个错误的设备,以便引发一个错误 if ( CommFd==-1 ) { int errnosv=errno; perror ( "HelloError" ); printf ( strerror ( errnosv ) ); } printf ( "\n" ); return EXIT_SUCCESS; }
输出的结果如下:
十一、正确使用errno
一个常见的错误用法如下所示:
if (somecall() == -1) { printf("somecall() failed\n"); if (errno == ...) { ... } }
当somecall引发了一个错误,errno被赋上值之后。你不应该直接使用errno进行其他的操作,在以上代码段中,errno可能被printf函数改变。如果我们要使用errno,最好的办法就是如下代码段所示的,把它保存在一个变量中,然后再使用。
if (somecall() == -1) { int errsv = errno; printf("somecall() failed\n"); if (errsv == ...) { ... } }
十二、extern关键字的使用
首先注意,extern关键字不是用来声明全局变量的。下面看一段错误的代码
//假设这是一个头文件MyCode.h extern char something[255];
然后我们想要在下面的源文件中引用something。
//MyCode.c #include <stdlib.h> #include <string.h>
#include <MyCode.h> int main(){ strcpy(something,"Hello world");//在这个地方编译器会爆出something没有定义(undefined错误) printf(something); }
因为extern不是这么用的。extern的出现是为了解决源文件中的东西,不能被其他源文件访问的问题。一般来说,假设我们要访问一个源文件(假设是源文件myCode.c)中的变量,那么我们需要先在源文件MyCode.c中定义一个变量,通常是在所有函数的开头。然后在这个源文件对应的头文件MyCode.h中用extern标志这个变量,那么当其他源文件MyCodeTwo.c引用了头文件MyCode,h的时候,就可以访问到MyCode.c中定义的变量。如下代码段所示。
//MyCode.c修改后 #include <stdlib.h> #include <string.h>
#include <MyCode.h> char something[255];//定义一个全局变量 int main(){ strcpy(something,"Hello world"); printf(something); }
//MyCodeTwo.c #include <stdlib.h> #include <string.h> #include <MyCode.h> int main(){ strcpy(something,"Hello world");//可以访问到MyCode.c的something printf(something); }
十三、Tar打包、压缩与解压缩到指定目录的方法
tar在linux上是常用的打包、压缩、加压缩工具,他的参数很多,这里仅仅列举常用的压缩与解压缩参数。
1、将整个/home/www/images 目录下的文件全部打包为 /home/www/images.tar
tar -cvf /home/www/images.tar /home/www/images ← 仅打包,不压缩 tar -zcvf /home/www/images.tar.gz /home/www/images ← 打包后,以gzip压缩
在参数f后面的压缩文件名是自己取的,习惯上用tar来做,如果加z参数,则以tar.gz 或tgz来代表gzip压缩过的tar file文件
2、将 /home/www/images.tar.gz 解压到/home/www下面
cd /home/www tar -zxvf /home/images.tar.gz
解压到指定的目录
tar -zxvf /home/images.tar.gz -C /specific dir
解包到指定的目录
tar xvf filename.tar -C /specific dir
作者:kissazi2
出处:http://www.cnblogs.com/kissazi2/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。