您的位置:首页 > 编程语言 > C语言/C++

c语言技巧--长期更新

2013-12-02 13:07 435 查看
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]\n", 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\n"

#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\n"

#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...\n");
printf("server start to work...\n");
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\n");
#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函数定义,尤其对大函数来说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: