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. 一种处理错误码的方法
不说什么,贴代码
这里,使用了宏来巧妙的处理了错误码的枚举和错误码详细信息
使用的技巧:## 宏连接两个宏定义, #连接字符串
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->>
client socket->connect->
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函数定义,尤其对大函数来说。
换成小写
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函数定义,尤其对大函数来说。
相关文章推荐
- Office使用技巧 长期更新
- 长期更新--零碎的小算法技巧
- c/c++ 奇技淫巧(一些c语言的技巧)
- Virtual Stdio 错误调试汇总(长期更新)
- 一些关于随着输入不断更新搜索结果的技巧
- 提高网站更新快照数量SEO技巧
- Linux 内核源代码的几个C语言技巧
- 编程错误集锦(长期更新)
- Mac上的软件的一些对开发者有用的使用技巧(持续更新)
- C语言已死(连载1)——趣味、通俗、实用的计算机达人成长之路之C语言高级技巧篇
- 在生产环境中安全执行更新删除SQL脚本的技巧
- [整理自用]c++错题(长期更新)
- 【不定期更新】游戏开发中的一些良好习惯与技术技巧
- git提交的常见错误(长期更新)
- C++/C语言入门成长全攻略:长期更新(最近更新日期2017-05-05)(第4次修改)
- C语言宏定义使用技巧
- 很酷的C语言技巧
- 几种注入绕过技巧(持续更新)
- oracle技巧-持续更新
- C语言中将绝对地址转换为函数指针以及跳转到内存指定位置处执行的技巧