• c语言技巧--长期更新


    1.   #define LOWER(c)            (unsigned char)(c | 0x20)

          换成小写

    2.   gcc -Wall -Werror //告警当成 错误来处理

    3.  gcc -Ox  //优化等级,一般debug搞成0, release搞成3

    4. 一种处理错误码的方法

    不说什么,贴代码

    #include <stdio.h>
    
    #define HTC_ERROR_MAP(xx)    
        xx(OK,         "SUCCESS")
        xx(INVALID_VERSION,     "invalid protocal version")
        xx(INVALID_STATUS,    "invalid protocal status")
    
    
    #define HTC_ERRNO_GEN(n,s) HTC_##n,
    
    #define HTC_ERRSTR_GEN(n,s) {"HTC_"#n,s},
    
    enum HTC_ERRNO
    {
        HTC_ERROR_MAP(HTC_ERRNO_GEN)
    };
    
    static struct
    {
        const char* name;
        const char* desc;    
    } protocal_err[] = {HTC_ERROR_MAP(HTC_ERRSTR_GEN)};
    
    
    int
    main()
    {
        enum HTC_ERRNO errno=HTC_OK;
        printf("name = [%s], desc = [%s]
    ", protocal_err[errno].name, protocal_err[errno].desc);
        return 0;
    }

    这里,使用了宏来巧妙的处理了错误码的枚举和错误码详细信息

    使用的技巧:## 宏连接两个宏定义, #连接字符串

    5. gcc -DXXXXX

       用来定义宏,一般用来写DEBUG宏

       CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_DEBUG=1     

     6. 封装数据结构,只有外部可见的数据结构才放在头文件中声明,定义仍然放在.c文件中

     7. Makefile如果想取得文件夹下全部文件

    $(wildcard $(PATH)/*.c)

    8..c转成.o文件 

    $(xxx:%.c=%.o)

    即可

    例子:

    $(ALLFILES:%.c=%.o)

     9. 使用void* 来适配任何类型数据

      void* data = (void*) 128;

    10. #define ULLONG_MAX  (uint64_t-1)

    uint64_t  为 typedef unsigned long int

    11. struct in_addr ip地址的数据结构

      保存一个属性,s_addr,一般是转换成网络序格式的32位ip地址

         可以使用inet_aton()函数来进行转换,

    12. printf 打印16进制的方法

       %X

       %08X 长度为8的16进制

    13. #error 

       该语法报用户自定义的错误信息

    14. socket(AF_INET,  SOCK_STREAM, 0)

    15. bind

      bind需要注意的是:struct sockaddr_in中的sin_port sin_addr都是网络序的

      bind第二个参数为了兼容各种sockaddr数据结构,使用struct sockaddr定义参数,需要转换格式

      所以 saddr.sin_family = AF_INET

        saddr.sin_port=htons(xxxx)

        struct addr_in addr;

        bzero(&addr, sizeof(addr));

        inet_pton(AF_INET, "xx,xx,xx,xx", &addr);

        saddr.sin_addr= addr;

        bind(AF_INET, (struct sockaddr*)(&saddr), INET_ADDRSTRLEN);(IPV4的长度)

    16. 在Accept 函数ok后,应该关掉socket返回的fd。结束accept,需要关闭accept函数返回的fd

    17.  server  socket -> bind->listen-> accept->fork   child -> close(sockfd)->>read--->close

                              parent ->close(connectfd) ->>accet->>

      

    /**
    
    **/
    
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <strings.h>
    
    #define USAGE "exec method: ./server
    "
    
    #define IP_ADDR     "127.0.0.1"
    #define PORT        2013
    #define IPV4        AF_INET
    #define BACKLOG        50
    //#define IPV4_ADDR_LEN     INET_ADDRSTR_LEN
    
    #define EXIT_MSG    "bye
    "
    
    #define handle_error(xx)
    do{perror(xx); exit(EXIT_FAILURE);}while(0)
    
    static void usage()
    {
        printf(USAGE);
    }
    
    static void proc_msg(int sockfd, int connectfd, pid_t name)
    {
        char buf[1024];
        int readlen=0;
        bzero(buf, sizeof(buf));
        printf("accept success...
    ");
        printf("server start to work...
    ");
        close(sockfd);
        for(;;)
        {
            bzero(buf, sizeof(buf));
            readlen = recv(connectfd, buf, 1024, 0);
            if(readlen >0)
            {
                printf("[%d] receive msg : %s", name,buf);
                if(strncmp(EXIT_MSG, buf) == 0)
                    break;                
            }
            if(readlen <= 0)
            {
                perror("fail read ...");
                break;
            }
        }
        
    }
    
    
    int main(int argc , char* argv[])
    {
        int            sockfd = 0;
        int             connectfd =0;
        struct     in_addr        inaddr;
        struct     sockaddr_in    skaddr;
        socklen_t          len;
        pid_t    child        = 0;
        char     buf[1024];
        int             readlen = 0;
        if(argc >1)
        {
            usage();
            return 1;
        }
        
        bzero(&inaddr, sizeof(struct in_addr));
        bzero(&skaddr, sizeof(struct sockaddr_in));
        
        skaddr.sin_family = IPV4;
        if(inet_pton(IPV4, IP_ADDR, &(skaddr.sin_addr)) == 0)
            handle_error("IP address is not avialabel...");
        
        skaddr.sin_port = htons(PORT);
            
        //scoket
        sockfd = socket(IPV4, SOCK_STREAM, 0);
        //bind
        if( bind(sockfd, (struct sockaddr*)(&skaddr), sizeof(struct sockaddr_in)) != 0)
            handle_error("bind fd failed...");        
        //listen
        if(listen(sockfd, BACKLOG) != 0)
            handle_error("listen fd failed...");
        
        len = sizeof(struct sockaddr_in);
        
        for(;;)
        {
            if((connectfd =accept(sockfd, (struct sockaddr*)(&skaddr), &len)) >0)
            {
                if((child = fork()) == 0)
                {
                    proc_msg(sockfd, connectfd, child);
                    close(connectfd);
                }
                close(connectfd);
            }
        }    
            
        return 0;
    }

           client    socket->connect->

    #include <stdio.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <strings.h>
    #include <unistd.h>
    #include <string.h>
    
    int main()
    {
        int             sockfd = 0;
        struct sockaddr_in     skaddr;
        char    buf[1024];    
    
        bzero(&skaddr, sizeof(skaddr));
        skaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &(skaddr.sin_addr));
        skaddr.sin_port = htons(2013);
        
        //socket    
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        //connect
        connect(sockfd, (struct sockaddr*)(&skaddr), sizeof(skaddr));
        
        //send
        for(;;)
        {
            bzero(buf, sizeof(buf));
            if(fgets(buf, 1024, stdin) != NULL)
            {
                send(sockfd, buf, strnlen(buf, 1024), 0);
            }        
        }
        sleep(3);
        close(sockfd);
    }

      18. killall -HUP xxxx 杀掉进程,进程名

          19. 僵死进程

    子进程已终 止,父进程尚未对其执行wait操作,子进程会转入“僵死”状态。内核为“僵死”状态的进程保留最少的信息量(进程标识,终止状态,资源使用信息),过后 父进程执行wait时可以获取子进程信息。只要僵死的进程不通过wait从系统中移去,它将会占据内核进程表中的一个栏位。如果进程表被填满,内核将不能 再产生新进程。如果父进程已终止,它的僵死子进程将由init进程收养,并自动执行wait将它们移去。

         请对子进程进程wait操作。

        20. 

    信号集是一个位向量,其中每一位对应着linux系统的一个信号。可使用如下函数对信号集进行处理:

    #include <signal.h>

    int sigemptyset(sigset_t * set);

    int sigfillset(sigset_t * set);

    int sigaddset(sigset_t * set);

    int sigdelset(sigset_t * set);

    sigemptyset将一个信号集清空;sigfillset将信号集的所有位置位;sigaddset函数将参数signo指定的信号所对应的位设置为1;sigdelset将signo的对应位设置为0。

     

     21. EINTR

    注意处理EINTR错误,errno返回时EINTR的时候,说明被信号中断导致的错误

    22. signal是软中断

    23. sigaction.sa_handler= func;

    24. 在处理SIGCHLD信号的函数中,while(waitpid(-1, &status, WNOHANG) > 0)来处理子进程的退出

    25. I/O复用的概念,想象一下这种场景,进程阻塞在读取I/O上,但是另一个I/O也在等待操作,那么这怎么办呢,这时候就需要用到I/O复用的概念了。

    26.  

     select 函数,用来等待多个I/O的读写状态,不再需要的等待一个I/O而阻塞了

    27.   socket连接握手

      client --> seq k ---> server

      client<---- seq J ack k+1 <-----server

          client ----> ack j+1---->server

       三次的消息flag分别是: seq, seq ack, ack     02, 12 , 10

    28. close 和shutdown的区别,

      共享套接字的情况下,close只是共享个数减 1, 只有到个数为零的时候,才会关闭套接字。

      而shutdown是等缓存中数据都取完后,直接关闭套接字,并不关心有多少个共享存在。但是套接字还是存在的,还需要用close来关闭

    29.  TIME_WAIT状态,是socket已经关闭后,保持的状态,一般是2MSL的时长

    30.  CLOSE_WAIT是被动关闭的一端,收到close后,没有close的状态

          应该处理这种情况

    if(recv(clientArray[i], recvBuf, 1024, 0) == 0)
    {

     #if __DEBUG__
    printf("process CLOSE_WAIT status ");
    #endif

      close(clientArray[i]);
      close(sockfd);
      index--;
    }

    31. linux kernel经常看到宏

    #define list_entry(ptr, type, member)
        container_of(ptr, type, member)

    #define container_of(ptr, type, member)                
    ({                                                       
        const typeof( ((type *)0)->member ) *__mptr = (ptr);
        (type *)( (char *)__mptr - offsetof(type,member) );
    })

    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

    offsetof宏是用来找到结构中,某个成员的偏移量

    container_of 宏是根据成员的指针找到容器的指针

    整个宏就是根据成员的指针找到容器的指针,ptr入参为成员的指针

     32.  inline使用

            inline函数不要超过10行代码,且不能包含循环、switch、if语句。

            在一个c文件中定义的inline函数是不能在其它c文件中直接使用,google推荐把inline函数定义在**-inl.h头文件中。

            不要过度使用inline函数定义,尤其对大函数来说。

  • 相关阅读:
    20169210《Linux内核原理与分析》第十周作业
    Collabtive 系统 SQL 注入实验(补充)
    20169211《Linux内核原理与分析》课程总结
    20169211《Linux内核原理及分析》第十二周作业
    20169211 《Linux内核原理与分析》第十一周作业
    20169211《Linux内核原理与分析》 第十周作业
    20169211《Linux内核原理与分析》 第九周作业
    20169210《Linux内核原理与分析》第八周作业
    20169211《linux内核原理与分析》第七周作业
    20169211《Linux内核原理与分析》第六周作业
  • 原文地址:https://www.cnblogs.com/unixshell/p/3453749.html
Copyright © 2020-2023  润新知