一些LinuxC的小知识点(一)

简介:

以下代码在Federo9上试验成功。

 

一、格式化输入16进制字符串

printf("Format:%.2x\n",10);

输入结果:

image

 

二、测试各类型的占用的字节数

复制代码
int main(int argc, char *argv[])
{
    int OutputHex = 1;
    unsigned char aValue=10;
    char Buffer[10];
    int len=sprintf(Buffer, OutputHex ? "%.2X  " : "%c", aValue);
    printf("Len:%d  Format:%s\n",len,Buffer);
    printf("Size Of char:%d\n",sizeof(char));
    printf("Size Of unsigned char:%d\n",sizeof(unsigned char));
    printf("Size Of int:%d\n",sizeof(int));
    return EXIT_SUCCESS;
}
复制代码

输入结果:

image

三、使用getopt函数来获取参数

当我们运行Linux下的C语言程序的时候,就可以非常方便地用getopt()这个函数将main参数中的argv提取出来,按需进行处理。函数的使用见以下代码段。

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int opt;

    while((opt = getopt(argc, argv, ":if:lr")) != -1) {
        switch(opt) {
        case 'i':
        case 'l':
        case 'r':
            printf("option: %c\n", opt);
            break;
        case 'f':
            printf("filename: %s\n", optarg);
            break;
        case ':':
            printf("option needs a value\n");
            break;
        case '?':
            printf("unknown option: %c\n", optopt);
            break;
        }
    }
    for(; optind < argc; optind++)
        printf("argument: %s\n", argv[optind]);
    exit(0);
}
复制代码

image

四、exit()和_exit()函数

1、_exit()执行后立即返回给内核,而exit()要先执行一些清除操作,然后将控制权交给内核。

2、exit中的参数exit_code为0代表进程正常终止,若为其他值表示程序执行过程中有错误发生。

五、用fprintf实现printf

大家可以通过以下代码看看两者的异同。

#include <stdio.h>
int main(void){
   printf("Hello world using printf\n");
   fprintf(stdout, "Hello world To stdout\n");
   fprintf(stderr, "Hello world To stderr\n");
}
stdoutstderr都是打印在屏幕的,因为标准错误输出流对象(stderr)就是定义为屏幕

输出结果:

image

小记:

关于 stdin、stdout、stderr 的说明如下:

stdout(Standard Output Stream)标准输出

stdin(Standard Input Stream)标准输入

stderr(Standard Error Output)标准错误输出

默认情况下,标准输入(stdin)指的从键盘上读数据,而标准输出(stdout)标准错误输出(stderr)是指屏幕

六、捕捉Esc按键

捕捉其他按键的程序跟这个差不多,总的思路就是通过判断键盘扫描码进行对应的处理。

复制代码
#include <stdio.h>
int main ( void )
{
    unsigned char aValue;
    printf ( "Enter a Char\n" );
    aValue = getchar();
    if ( aValue == '\x1b' )
    {
        printf ( "Esc pressed %c\n",aValue );
    }else
    {
        printf ( "Esc Not pressed%c\n",aValue );
    }
}
复制代码

结果:

image

七、避免getchar()读入用于结束输入的换行符

复制代码
#include <stdio.h>
int main ( void )
{
    unsigned char aValue;
    do{
        printf ( "Enter a Char\n" );
        do{
            aValue = getchar();
        }while(aValue=='\n' );//避免读入\n
        if ( aValue == '\x1b' )
        {
            printf ( "Esc pressed.\t \n" );
        }else
        {
            printf ( "Esc Not pressed.\t%c Pressed\n",aValue );
        }
    }while(aValue!='q' );//读到q的时候,退出
}
复制代码

八、如果stdout已经被重定向,可以将消息写到stderr(标准错误输出),stderr不会被重定向。

另外,Linux是一个多用户的系统,我们可以通过利用’/dev/tty‘正确地将信息输出到用户正在使用的终端上。

九、fileno()函数

功    能:把文件流指针转换成文件描述符 
相关函数:open, fopen 
表头文件:#include <stdio.h> 
定义函数:int fileno(FILE *stream) 
函数说明:fileno()用来取得参数stream指定的文件流所使用的文件描述词 
返回值  :返回和stream文件流对应的文件描述符。如果失败,返回-1。 
范例:

复制代码
#include <stdio.h> 
main() 
{ 
     FILE   *fp; 
     int   fd; 
     fp = fopen("/etc/passwd", "r"); 
     fd = fileno(fp); 
     printf("fd = %d\n", fd); 
     fclose(fp); 
}
复制代码

    文件描述词是Linux编程中的一个术语。当一个文件打开后,系统会分配一部分资源来保存该文件的信息,以后对文件的操作就可以直接引用该部分资源了。文件描述词可以认为是该部分资源的一个索引,在打开文件时返回。在使用fcntl函数对文件的一些属性进行设置时就需要一个文件描述词参数。 
    以前知道,当程序执行时,就已经有三个文件流打开了,它们分别是标准输入stdin,标准输出stdout和标准错误输出stderr。和流式文件相对应的是,也有三个文件描述符被预先打开,它们分别是0,1,2,代表标准输入、标准输出和标准错误输出。 
    需要指出的是,上面的流式文件输入、输出和文件描述符的输入输出方式不能混用,否则会造成混乱。

 

十、fgets会自动将字符串的最后一位置为’\0’

请看一下下面的代码,我们期待输入’12345678’(8个数),用fgets函数输出’12345678’(8个数).

复制代码
#include <stdio.h> /*标准输入输出定义*/
#define PASSWORD_LEN 8

int main(){
        char password[PASSWORD_LEN+1];
        printf("请输入您的密码\n");
        fgets(password,PASSWORD_LEN,stdin);
        printf("您输入的密码是:%s\n",password);
}
复制代码

输出结果:

image

我们可以看出,输出的结果并不是我们所期望的,但是我们也命名在fget里面写了,我们期望的获取8个数(PASSWORD_LEN==8)。原来fget一次调用只能传输n-1个字符,因为它必须把空字节’\0’加上以结束字符串。也就是,如果我们要让输出跟我们的期望相符,那么我们要修改fget函数的参数,如下代码段所示。

fgets(password,PASSWORD_LEN+1,stdin);

 

 

十一、malloc函数的学习

复制代码
#include <stdlib.h>
#include <string.h>
int main(){
    char * s="123.33";    
    int i=0;
    char **endp= (char **)malloc(sizeof(int)*5);//先分配五个整型数据空间,这5个空间就可以用来存储每个二级指针的首地址了。
   
    for(i=0;i<5;i++){
        endp[i]=(char *)malloc(sizeof(char)*5);//再为每个二级指针分配5个char型数据空间,这样,每个元素也就拥有了各自的家。只是这5个空间是用来存储char型的!!endp[0]5个,endp[1]5个等等
    }

    strcpy(endp[0],"12345");
    for(i=0;i<5;i++){
        printf("endp[%d] is :%s\t,endp的地址是%d\n",i,*(endp+i),endp+i);//可以看出刚分配完的时候,所有的5个endp一维数组的内容都是空
    }
    for(i=0;i<5;i++){
        printf("endp[0][%d] is :%c,\tendp[0][%d]的地址是%d\n",i,*((*endp)+i),i,((*endp)+i)    );
    }

}
复制代码

其实可以用malloc动态分配二维数组空间的。

运行结果:

image

 

十二、从一段代码中看printf的执行顺序(编译环境为gcc)

printf("++a=%d,a++=%d\n",++a,a++);

结果分析:

如果输出++a=1,a++=1,那么说明函数是从左执行到右的;如果++a=2,a++=0,那么说明函数是从右执行到左的。

结果截图:

image

 

 

十三、获取系统当前的时间

首先,让我们先看看两个跟时间有关的类型time_t,tm。

time_t:它是一个大到能容纳以秒计算的日期和时间的整数类型。在32位系统上就是32位的的。

tm结构体被定义为至少包含下表所示的成员。

image

以下代码段展示的是如何获取当前的时间

复制代码
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main ( int argc, char *argv[] )
{
    struct tm *tm_ptr,timestruct;
    time_t the_time;
    char buf[256];      //用来保存时间字符串
    char *result;       //用来保存不能成功转化的字符串指针
    ( void ) time ( &the_time );
    printf ( "the current time is : %s",ctime ( &the_time ) );//获取当前的时间
    tm_ptr = &timestruct;
    result = strptime ( ctime ( &the_time ),"%a %b %d %H:%M:%S %Y", tm_ptr );
    printf ( "strptime gives:\n" );
    printf ( "date: %02d/%02d/%02d\n",
             tm_ptr->tm_year % 100, tm_ptr->tm_mon+1, tm_ptr->tm_mday );
    printf ( "time: %02d:%02d:%02d\n",
             tm_ptr->tm_hour, tm_ptr->tm_min,tm_ptr->tm_sec );
    exit ( EXIT_SUCCESS );
}
复制代码

十四、设置文件的访问模式,可以利用fcntl.

十五、利用inline可以解决一些频繁调用的小涵数大量消耗栈空间或是叫栈内存的问题

      在c中,为了解决一些频繁调用的小涵数大量消耗栈空间或是叫栈内存的问题,特别的引入了inline修饰符,表示为内联涵数。 
      可能说到这里,很多人还不明白什么是栈空间,其实栈空间就是指放置程式的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足所造成的程式出错的问题,涵数的死循环递归调用的最终结果就是导致栈内存空间枯竭。 
下面我们来看一个例子

复制代码
#include <stdio.h>

inline char* dbtest ( int a ); //函数原形声明为inline即:内联涵数

int main()
{
    int i = 0;
    for ( i=1;i<=10;i )
    {
        printf ( "%d is %s\n",i,dbtest ( i ) );
    }
    return 0;
}

char* dbtest ( int a ) //这里不用再次inline,当然加上inline也是不会出错的
{
    return ( a%2>0 ) ?"":"";
}
复制代码

 

     上面的例子就是标准的内联涵数的用法,使用inline修饰带来的好处我们表面看不出来,其实在内部的工作就是在每个for循环的内部任何调用 dbtest(i)的地方都换成了(i%2>0)?"奇":"偶"这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。 
      说到这里很多人可能会问,既然inline这么好,还不如把所谓的函数都声明成inline,嗯,这个问题是要注意的,inline的使用是有所限制的,inline只适合涵数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如while switch,并且不能内联函数本身不能是直接递归函数(自己内部还调用自己的函数)。 
      说到这里我们不得不说一下在c语言中广泛被使用的#define语句,是的define的确也能够做到inline的这些工作,但是define是会产生副作用的,尤其是不同类型参数所导致的错误,由此可见inline有更强的约束性和能够让编译器检查出更多错误的特性,在c 中是不推荐使用define的。

 

参考

《Linux程序设计 第四版》

本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/3148055.html如需转载请自行联系原作者


kissazi2

 

 

 

 

 

linux c inline


相关文章
|
6月前
|
编译器 C语言 C++
lesson0-C++入门 2
lesson0-C++入门
35 0
|
6月前
|
编译器 C语言 C++
lesson0-C++入门 1
lesson0-C++入门
29 0
|
6月前
|
存储 安全 编译器
lesson0-C++入门 3
lesson0-C++入门
24 0
|
8月前
|
存储 自然语言处理 算法
Lesson1——数据结构前言
Lesson1——数据结构前言
|
11月前
|
存储 编译器 C语言
LinuxC字符串处理
LinuxC字符串处理
42 0
|
Linux
linux基本功系列之mkdir命令实战
linux基本功系列之mkdir命令实战
58 0
linux基本功系列之mkdir命令实战
|
Linux
linux基本功系列之cp命令实战
linux基本功系列之cp命令实战
86 0
linux基本功系列之cp命令实战
|
小程序 编译器 C语言
|
编译器 程序员 C语言
|
存储 安全 Java