2025
01
18
2012
06
30
strncpyを使った安全な文字列コピー(C言語)
コピー元の文字列の長さが不明な時用のメモリ破壊を起こさない 文字列コピーの方法について、strncpyの動作を見ながら確認したメモ 結論から言うと strncpy(dst, src, DST_BUFF_LEN); dst[DST_BUFF_LEN-1] = '\0'; すれば破壊は起きない、ただsrcをコピーしきれないことがある。 下記のソースを試したコンパイラバージョンは gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)です。
ソースコード
/* nex2t_strncpy.c */ #include <stdio.h> #include <string.h> #define EX_STR "0123456789abcdefghij" #define EX_STR2 "01234" #define BUF_LEN 16 #define DEBUG_LINE "---------------------------------------------------------\n" int main(void) { int i; char buf[BUF_LEN]; /* -------------------------------------------------------------- */ printf(DEBUG_LINE); printf("use buffer buf[BUF_LEN] BUF_LEN=%d\n", BUF_LEN); printf(DEBUG_LINE); printf("EX_STR:%s [strlen(EX_STR):%ld, sizeof(EX_STR):%ld]\n", EX_STR, strlen(EX_STR), sizeof(EX_STR)); printf(" (over buf[BUF_LEN] size!!)\n"); printf(DEBUG_LINE); printf("EX_STR2:%s [strlen(EX_STR2):%ld, sizeof(EX_STR2):%ld]\n", EX_STR2, strlen(EX_STR2), sizeof(EX_STR2)); printf(" (not over buf[BUF_LEN] size)\n"); printf(DEBUG_LINE "\n"); /* ---- Init after ----------------------------------------------- */ printf("Init after\n"); printf(DEBUG_LINE); for (i = 0; i < BUF_LEN; i++) { buf[i] = '\0'; } for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); /* ---- Normal_1 ------------------------------------------------ */ printf("Normal_1\n"); printf(DEBUG_LINE); strncpy(buf, EX_STR, 5); printf("strncpy(buf, EX_STR, 5);\n"); printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf, strlen(buf), sizeof(buf)); for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); /* init */ for (i = 0; i < BUF_LEN; i++) { buf[i] = '\0'; } /* ---- Normal_2 ----------------------------------------------- */ printf("Normal_2\n"); printf(DEBUG_LINE); strncpy(buf, EX_STR, BUF_LEN); printf("strncpy(buf, EX_STR, BUF_LEN);\n"); printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf, strlen(buf), sizeof(buf)); for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); printf("***Not write '\\0' automatically!! (buf[%d] = %d)\n", BUF_LEN-1, buf[BUF_LEN-1]); printf("***Not write buf[BUF_LEN] (buf[%d] = %d)\n\n", BUF_LEN, buf[BUF_LEN]); /* not init */ /* for (i = 0; i < BUF_LEN; i++) { buf[i] = '\0'; } */ /* ---- Normal_3 ----------------------------------------------- */ printf("Normal_3\n"); printf(DEBUG_LINE); strncpy(buf, EX_STR2, BUF_LEN); printf("strncpy(buf, EX_STR2, BUF_LEN);\n"); printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf, strlen(buf), sizeof(buf)); for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); printf("***automatically write '\\0' to buf[15]\n"); /* ---- Extra ------------------------------------------------- */ printf("\nExtra\n"); printf(DEBUG_LINE); strncpy(buf, EX_STR, 0); printf("strncpy(buf, EX_STR, 0);\n"); printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf, strlen(buf), sizeof(buf)); for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); printf("Not write any.\n\n"); /* ---- Right usage ------------------------------------------- */ printf("Right usage\n"); printf(DEBUG_LINE); strncpy(buf, EX_STR, BUF_LEN); buf[BUF_LEN-1] = '\0'; for (i = 0; i < BUF_LEN; i++) { printf("buf[%d] = %d\n", i, buf[i]); } printf("buf[BUF_LEN] = %d (secretly watch.)\n\n", buf[BUF_LEN]); printf("strncpy(buf, EX_STR, BUF_LEN); after buf[BUF_LEN-1] = '\\0';"); return 0; }
コンパイル例
gcc -W -Wall -o nex2t_strncpy nex2t_strncpy.c
実行結果
./strncpy --------------------------------------------------------- use buffer buf[BUF_LEN] BUF_LEN=16 --------------------------------------------------------- EX_STR:0123456789abcdefghij [strlen(EX_STR):20, sizeof(EX_STR):21] (over buf[BUF_LEN] size!!) --------------------------------------------------------- EX_STR2:01234 [strlen(EX_STR2):5, sizeof(EX_STR2):6] (not over buf[BUF_LEN] size) --------------------------------------------------------- Init after --------------------------------------------------------- buf[0] = 0 buf[1] = 0 buf[2] = 0 buf[3] = 0 buf[4] = 0 buf[5] = 0 buf[6] = 0 buf[7] = 0 buf[8] = 0 buf[9] = 0 buf[10] = 0 buf[11] = 0 buf[12] = 0 buf[13] = 0 buf[14] = 0 buf[15] = 0 buf[BUF_LEN] = 0 (secretly watch.) Normal_1 --------------------------------------------------------- strncpy(buf, EX_STR, 5); result:string:01234 [strlen(buf):5, sizeof(buf):16] buf[0] = 48 buf[1] = 49 buf[2] = 50 buf[3] = 51 buf[4] = 52 buf[5] = 0 buf[6] = 0 buf[7] = 0 buf[8] = 0 buf[9] = 0 buf[10] = 0 buf[11] = 0 buf[12] = 0 buf[13] = 0 buf[14] = 0 buf[15] = 0 buf[BUF_LEN] = 0 (secretly watch.) Normal_2 --------------------------------------------------------- strncpy(buf, EX_STR, BUF_LEN); result:string:0123456789abcdef [strlen(buf):16, sizeof(buf):16] buf[0] = 48 buf[1] = 49 buf[2] = 50 buf[3] = 51 buf[4] = 52 buf[5] = 53 buf[6] = 54 buf[7] = 55 buf[8] = 56 buf[9] = 57 buf[10] = 97 buf[11] = 98 buf[12] = 99 buf[13] = 100 buf[14] = 101 buf[15] = 102 buf[BUF_LEN] = 0 (secretly watch.) ***Not write '\0' automatically!! (buf[15] = 102) ***Not write buf[BUF_LEN] (buf[16] = 0) Normal_3 --------------------------------------------------------- strncpy(buf, EX_STR2, BUF_LEN); result:string:01234 [strlen(buf):5, sizeof(buf):16] buf[0] = 48 buf[1] = 49 buf[2] = 50 buf[3] = 51 buf[4] = 52 buf[5] = 0 buf[6] = 0 buf[7] = 0 buf[8] = 0 buf[9] = 0 buf[10] = 0 buf[11] = 0 buf[12] = 0 buf[13] = 0 buf[14] = 0 buf[15] = 0 buf[BUF_LEN] = 0 (secretly watch.) ***automatically write '\0' to buf[15] Extra --------------------------------------------------------- strncpy(buf, EX_STR, 0); result:string:01234 [strlen(buf):5, sizeof(buf):16] buf[0] = 48 buf[1] = 49 buf[2] = 50 buf[3] = 51 buf[4] = 52 buf[5] = 0 buf[6] = 0 buf[7] = 0 buf[8] = 0 buf[9] = 0 buf[10] = 0 buf[11] = 0 buf[12] = 0 buf[13] = 0 buf[14] = 0 buf[15] = 0 buf[BUF_LEN] = 0 (secretly watch.) Not write any. Right usage --------------------------------------------------------- buf[0] = 48 buf[1] = 49 buf[2] = 50 buf[3] = 51 buf[4] = 52 buf[5] = 53 buf[6] = 54 buf[7] = 55 buf[8] = 56 buf[9] = 57 buf[10] = 97 buf[11] = 98 buf[12] = 99 buf[13] = 100 buf[14] = 101 buf[15] = 0 buf[BUF_LEN] = 0 (secretly watch.) strncpy(buf, EX_STR, BUF_LEN); after buf[BUF_LEN-1] = '\0';
検索用タグ C言語 strncpy 安全
PR
2012/06/30 (Sat.) Comment(0) C言語
2012
06
24
自己参照型双方向リスト(C言語)
現在ゲーム中のユーザ管理するのにリスト構造使おうとちょっと作ったので置いておく。 自己参照型双方向リストです。
ソースコード
/* nex2t_list.c */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <netdb.h> #define RET_SUCCESS 0 #define RET_NO_ENTRY 1 #define RET_NO_MATCH_ENTRY 2 #define RET_NO_EXIST 0 #define RET_EXIST 1 #define DEBUG_LINE "------------------------------------------\n" typedef struct client_info { pid_t pid; char ip[NI_MAXHOST]; char port[NI_MAXSERV]; } cli_info_t; typedef struct client_info_node { struct client_info_node *next; struct client_info_node *prev; cli_info_t ent; } cli_info_node_t; typedef struct client_info_list { struct client_info_node *head; struct client_info_node *tail; } cli_info_list_t; void test(void); void create_info(cli_info_t *info, pid_t pid, const char ip[], const char port[]); void list_init(cli_info_list_t *list); void list_exit(cli_info_list_t *list); void list_add(cli_info_list_t *list, const cli_info_t *info); int list_del_head(cli_info_list_t *list); int list_del_tail(cli_info_list_t *list); int list_del_match_pid(cli_info_list_t *list, pid_t pid); int list_del_match_ip(cli_info_list_t *list, const char ip[]); int list_del_match_port(cli_info_list_t *list, const char port[]); int list_del_match(cli_info_list_t *list, const cli_info_t *info); int is_exist_cli_info_pid(const cli_info_list_t *list, pid_t pid); int is_exist_cli_info_ip(const cli_info_list_t *list, const char ip[]); int is_exist_cli_info_port(const cli_info_list_t *list, const char port[]); int is_exist_cli_info(const cli_info_list_t *list, const cli_info_t *info); void list_show(const cli_info_list_t *list); void list_show_match_pid(const cli_info_list_t *list, pid_t pid); void list_show_match_ip(const cli_info_list_t *list, const char ip[]); void list_show_match_port(const cli_info_list_t *list, const char port[]); void list_show_match(const cli_info_list_t *list, const cli_info_t *info); int main(void) { test(); return 0; } void create_info(cli_info_t *info, pid_t pid, const char ip[], const char port[]) { info->pid = pid; strcpy(info->ip, ip); strcpy(info->port, port); } void list_init(cli_info_list_t *list) { list->head = NULL; list->tail = NULL; } void list_add(cli_info_list_t *list, const cli_info_t *info) { cli_info_node_t *node; cli_info_node_t *node_tmp; node = (cli_info_node_t *)malloc(sizeof(cli_info_node_t)); node->ent.pid = info->pid; strcpy(node->ent.ip, info->ip); strcpy(node->ent.port, info->port); if (list->head == NULL) { /* first add */ list->head = node; list->tail = node; node->prev = NULL; node->next = NULL; } else { node_tmp = list->head; while (node_tmp->next != NULL) { node_tmp = node_tmp->next; } node_tmp->next = node; node->next = NULL; node->prev = node_tmp; list->tail = node; } } int list_del_head(cli_info_list_t *list) { cli_info_node_t *node_next_keep; if (list->head == NULL) { return RET_NO_ENTRY; } else if (list->head->next == NULL) { free(list->head); list->head = NULL; list->tail = NULL; } else { node_next_keep = list->head->next; free(node_next_keep->prev); list->head = node_next_keep; list->head->prev = NULL; } return RET_SUCCESS; } int list_del_tail(cli_info_list_t *list) { cli_info_node_t *node_prev_keep; if (list->tail == NULL) { return RET_NO_ENTRY; } else if (list->tail->prev == NULL) { free(list->tail); list->head = NULL; list->tail = NULL; } else { node_prev_keep = list->tail->prev; free(list->tail); list->tail = node_prev_keep; list->tail->next = NULL; } return RET_SUCCESS; } int list_del_match_pid(cli_info_list_t *list, pid_t pid) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_ENTRY; } node = list->head; do { if (i != 1) { node = node->next; } if (node->ent.pid == pid) { if ((node->prev == NULL) && (node->next == NULL)) { list->head = NULL; list->tail = NULL; } else if (node->prev == NULL) { list->head = node->next; node->next->prev = NULL; } else if (node->next == NULL) { list->tail = node->prev; node->prev->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } free(node); return RET_SUCCESS; } i++; } while (node->next != NULL); return RET_NO_MATCH_ENTRY; } int list_del_match_ip(cli_info_list_t *list, const char ip[]) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_ENTRY; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.ip, ip)) { if ((node->prev == NULL) && (node->next == NULL)) { list->head = NULL; list->tail = NULL; } else if (node->prev == NULL) { list->head = node->next; node->next->prev = NULL; } else if (node->next == NULL) { list->tail = node->prev; node->prev->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } free(node); return RET_SUCCESS; } i++; } while (node->next != NULL); return RET_NO_MATCH_ENTRY; } int list_del_match_port(cli_info_list_t *list, const char port[]) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_ENTRY; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.port, port)) { if ((node->prev == NULL) && (node->next == NULL)) { list->head = NULL; list->tail = NULL; } else if (node->prev == NULL) { list->head = node->next; node->next->prev = NULL; } else if (node->next == NULL) { list->tail = node->prev; node->prev->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } free(node); return RET_SUCCESS; } i++; } while (node->next != NULL); return RET_NO_MATCH_ENTRY; } int list_del_match(cli_info_list_t *list, const cli_info_t *info) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_ENTRY; } node = list->head; do { if (i != 1) { node = node->next; } if ((node->ent.pid == info->pid) && !strcmp(node->ent.ip, info->ip) && (!strcmp(node->ent.port, info->port))) { if ((node->prev == NULL) && (node->next == NULL)) { list->head = NULL; list->tail = NULL; } else if (node->prev == NULL) { list->head = node->next; node->next->prev = NULL; } else if (node->next == NULL) { list->tail = node->prev; node->prev->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } free(node); return RET_SUCCESS; } i++; } while (node->next != NULL); return RET_NO_MATCH_ENTRY; } void list_show(const cli_info_list_t *list) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { printf("NO ENTRY.\n"); return; } node = list->head; do { if (i != 1) { node = node->next; } printf("[%d] pid:%d, ip:%s, port:%s\n", i++, node->ent.pid, node->ent.ip, node->ent.port); } while (node->next != NULL); } void list_show_match_pid(const cli_info_list_t *list, pid_t pid) { int i = 1, match_flag = 0; cli_info_node_t *node; if (list->head == NULL) { printf("NO_ENTRY.\n"); return; } node = list->head; do { if (i != 1) { node = node->next; } if (node->ent.pid == pid) { printf("[%d] pid:%d, ip:%s, port:%s\n", i, node->ent.pid, node->ent.ip, node->ent.port); match_flag = 1; } i++; } while (node->next != NULL); if (!match_flag) { printf("NO MATCH ENTRY pid:%d\n", pid); } } void list_show_match_ip(const cli_info_list_t *list, const char ip[]) { int i = 1, match_flag = 0; cli_info_node_t *node; if (list->head == NULL) { printf("NO_ENTRY.\n"); return; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.ip, ip)) { printf("[%d] pid:%d, ip:%s, port:%s\n", i, node->ent.pid, node->ent.ip, node->ent.port); match_flag = 1; } i++; } while (node->next != NULL); if (!match_flag) { printf("NO MATCH ENTRY ip:%s\n", ip); } } void list_show_match_port(const cli_info_list_t *list, const char port[]) { int i = 1, match_flag = 0; cli_info_node_t *node; if (list->head == NULL) { printf("NO ENTRY.\n"); return; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.port, port)) { printf("[%d] pid:%d, ip:%s, port:%s\n", i, node->ent.pid, node->ent.ip, node->ent.port); match_flag = 1; } i++; } while (node->next != NULL); if (!match_flag) { printf("NO MATCH ENTRY port:%s\n", port); } } void list_show_match(const cli_info_list_t *list, const cli_info_t *info) { int i = 1, match_flag = 0; cli_info_node_t *node; if (list->head == NULL) { printf("NO ENTRY\n"); return; } node = list->head; do { if (i != 1) { node = node->next; } if ((node->ent.pid == info->pid) && !strcmp(node->ent.ip, info->ip) && (!strcmp(node->ent.port, info->port))) { printf("[%d] pid:%d, ip:%s, port:%s\n", i, node->ent.pid, node->ent.ip, node->ent.port); match_flag = 1; } i++; } while (node->next != NULL); if (!match_flag) { printf("NO MATCH ENTRY pid:%d, ip:%s, port:%s\n", info->pid, info->ip, info->port); } } int is_exist_cli_info_pid(const cli_info_list_t *list, pid_t pid) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_EXIST; } node = list->head; do { if (i != 1) { node = node->next; } if (node->ent.pid == pid) { return RET_EXIST; } i++; } while (node->next != NULL); return RET_NO_EXIST; } int is_exist_cli_info_ip(const cli_info_list_t *list, const char ip[]) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_EXIST; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.ip, ip)) { return RET_EXIST; } i++; } while (node->next != NULL); return RET_NO_EXIST; } int is_exist_cli_info_port(const cli_info_list_t *list, const char port[]) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_EXIST; } node = list->head; do { if (i != 1) { node = node->next; } if (!strcmp(node->ent.port, port)) { return RET_EXIST; } i++; } while (node->next != NULL); return RET_NO_EXIST; } int is_exist_cli_info(const cli_info_list_t *list, const cli_info_t *info) { int i = 1; cli_info_node_t *node; if (list->head == NULL) { return RET_NO_EXIST; } node = list->head; do { if (i != 1) { node = node->next; } if ((node->ent.pid == info->pid) && !strcmp(node->ent.ip, info->ip) && (!strcmp(node->ent.port, info->port))) { return RET_EXIST; } i++; } while (node->next != NULL); return RET_NO_EXIST; } void list_exit(cli_info_list_t *list) { cli_info_node_t *node_tmp; cli_info_node_t *node_keep; if (list->head == NULL) { return; /* no entry */ } node_tmp = list->head; do { node_keep = node_tmp->next; free(node_tmp); node_tmp = node_keep; } while (node_tmp != NULL); } void test(void) { cli_info_list_t list; cli_info_t info; list_init(&list); printf("first list state.\n"); create_info(&info, 1003, "192.168.1.3", "10003"); list_add(&list, &info); create_info(&info, 1004, "192.168.1.4", "10004"); list_add(&list, &info); create_info(&info, 1005, "192.168.1.5", "10005"); list_add(&list, &info); create_info(&info, 1006, "192.168.1.6", "10006"); list_add(&list, &info); printf(DEBUG_LINE); list_show(&list); printf(DEBUG_LINE "\n"); printf("list_show_match test\n"); printf(DEBUG_LINE); list_show_match_pid(&list, 1005); list_show_match_pid(&list, 1007); list_show_match_ip(&list, "192.168.1.10"); list_show_match_ip(&list, "192.168.1.6"); list_show_match_port(&list, "10009"); list_show_match_port(&list, "10003"); create_info(&info, 1003, "192.168.1.5", "10003"); list_show_match(&list, &info); create_info(&info, 1003, "192.168.1.3", "10003"); list_show_match(&list, &info); printf(DEBUG_LINE "\n"); printf("is_exist_cli_info test (equal param list_show_match test)\n"); printf(DEBUG_LINE); printf("%d\n", is_exist_cli_info_pid(&list, 1005)); printf("%d\n", is_exist_cli_info_pid(&list, 1007)); printf("%d\n", is_exist_cli_info_ip(&list, "192.168.1.10")); printf("%d\n", is_exist_cli_info_ip(&list, "192.168.1.6")); printf("%d\n", is_exist_cli_info_port(&list, "10009")); printf("%d\n", is_exist_cli_info_port(&list, "10003")); create_info(&info, 1003, "192.168.1.5", "10003"); printf("%d\n", is_exist_cli_info(&list, &info)); create_info(&info, 1003, "192.168.1.3", "10003"); printf("%d\n", is_exist_cli_info(&list, &info)); printf(DEBUG_LINE "\n"); printf("list_add test\n"); printf(DEBUG_LINE); create_info(&info, 2003, "192.168.2.3", "20003"); list_add(&list, &info); create_info(&info, 2004, "192.168.2.4", "20004"); list_add(&list, &info); list_show(&list); printf(DEBUG_LINE "\n"); printf("list_del test\n"); printf(DEBUG_LINE); list_del_head(&list); list_del_tail(&list); list_show(&list); printf(DEBUG_LINE); list_del_match_pid(&list, 1003); list_del_match_pid(&list, 1004); /* del */ list_show(&list); printf(DEBUG_LINE); list_del_match_ip(&list, "192.168.1.5"); /* del */ list_del_match_ip(&list, "192.168.1.7"); list_show(&list); printf(DEBUG_LINE); list_del_match_port(&list, "10006"); /* del */ list_del_match_port(&list, "10005"); list_show(&list); printf(DEBUG_LINE); create_info(&info, 1003, "192.168.1.5", "10003"); list_del_match(&list, &info); create_info(&info, 2003, "192.168.2.3", "20003"); /* del */ list_del_match(&list, &info); list_show(&list); printf(DEBUG_LINE); list_exit(&list); }
コンパイル例
gcc -W -Wall -o nex2t_list nex2t_list.c
実行結果
./list first list state. ------------------------------------------ [1] pid:1003, ip:192.168.1.3, port:10003 [2] pid:1004, ip:192.168.1.4, port:10004 [3] pid:1005, ip:192.168.1.5, port:10005 [4] pid:1006, ip:192.168.1.6, port:10006 ------------------------------------------ list_show_match test ------------------------------------------ [3] pid:1005, ip:192.168.1.5, port:10005 NO MATCH ENTRY pid:1007 NO MATCH ENTRY ip:192.168.1.10 [4] pid:1006, ip:192.168.1.6, port:10006 NO MATCH ENTRY port:10009 [1] pid:1003, ip:192.168.1.3, port:10003 NO MATCH ENTRY pid:1003, ip:192.168.1.5, port:10003 [1] pid:1003, ip:192.168.1.3, port:10003 ------------------------------------------ is_exist_cli_info test (equal param list_show_match test) ------------------------------------------ 1 0 0 1 0 1 0 1 ------------------------------------------ list_add test ------------------------------------------ [1] pid:1003, ip:192.168.1.3, port:10003 [2] pid:1004, ip:192.168.1.4, port:10004 [3] pid:1005, ip:192.168.1.5, port:10005 [4] pid:1006, ip:192.168.1.6, port:10006 [5] pid:2003, ip:192.168.2.3, port:20003 [6] pid:2004, ip:192.168.2.4, port:20004 ------------------------------------------ list_del test ------------------------------------------ [1] pid:1004, ip:192.168.1.4, port:10004 [2] pid:1005, ip:192.168.1.5, port:10005 [3] pid:1006, ip:192.168.1.6, port:10006 [4] pid:2003, ip:192.168.2.3, port:20003 ------------------------------------------ [1] pid:1005, ip:192.168.1.5, port:10005 [2] pid:1006, ip:192.168.1.6, port:10006 [3] pid:2003, ip:192.168.2.3, port:20003 ------------------------------------------ [1] pid:1006, ip:192.168.1.6, port:10006 [2] pid:2003, ip:192.168.2.3, port:20003 ------------------------------------------ [1] pid:2003, ip:192.168.2.3, port:20003 ------------------------------------------ NO ENTRY. ------------------------------------------
検索用タグ C言語 双方向リスト 自己参照型
2012/06/24 (Sun.) Comment(0) C言語
2012
05
30
可変長引数を使ってログメッセージ作成(C言語)
syslogに出力するのに、可変長引数使ってログメッセージ出力してやろうと 思って少しやったのでメモ。以下ソースはエラー処理とか細かいところはやってません (C言語でsyslog()に出力するのはまた別の記事でやろうかと思います)
ソースコード
/* nex2t_syslog.c */ #include <stdio.h> #include <stdarg.h> #define LOG_MESSAGE1 "[20000]: system info\n" #define LOG_MESSAGE2 "[20001]: system error(%d, %d)\n" #define LOG_MAIN 1 /* where? */ void nex2t_syslog(char *fmt, ...); int main(void) { nex2t_syslog(LOG_MESSAGE1); nex2t_syslog(LOG_MESSAGE2, LOG_MAIN, 0); /* ~hogehoge~ */ nex2t_syslog(LOG_MESSAGE2, LOG_MAIN, 7); return 0; } void nex2t_syslog(char *fmt, ...) { char *p; int ival; va_list ap; va_start(ap, fmt); for (p = fmt; *p; p++) { if (*p != '%') { putchar(*p); continue; } p++; ival = va_arg(ap, int); printf("%d", ival); } va_end(ap); }
コンパイル例
gcc -W -Wall -o nex2t_syslog nex2t_syslog.c
実行結果
./nex2t_syslog [20000]: system info [20001]: system error(1, 0) [20001]: system error(1, 7)
検索用タグ C言語 可変長引数
2012/05/30 (Wed.) Comment(0) C言語
2012
05
27
パイプで双方向プロセス間通信(C言語)
ファイル整理してたら出てきたのでメモ
ソースコード
/* pipe.c */ #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define BUF_LEN 256 int main(void) { int fd[2], ret; char buf[BUF_LEN]; pid_t pid; if ((ret = pipe(fd)) == -1) { perror("pipe"); return -1; } if ((ret = fork()) == -1) { perror("fork"); return -1; } else if (ret == 0) { pid = getpid(); printf("[pid:%d] I'm child\n", (int)pid); write(fd[1], "child wrote", 13); read(fd[0], buf, BUF_LEN); printf("[pid:%d] from parent:[%s]\n", (int)pid, buf); } else { pid = getpid(); printf("[pid:%d] I'm parent\n", (int)pid); write(fd[1], "parent wrote", 14); read(fd[0], buf, BUF_LEN); printf("[pid:%d] from child:[%s]\n", (int)pid, buf); wait(&ret); } return 0; }
実行結果
./pipe [pid:13330] I'm parent [pid:13330] from child:[parent wrote] [pid:13331] I'm child [pid:13331] from parent:[child wrote]
検索用タグ C言語 プロセス間通信
2012/05/27 (Sun.) Comment(0) C言語
2012
05
27
値渡しとポインタ渡しで実行速度比較(C言語)
「C言語には値渡ししかないんだよ」みたいな突っ込みは置いておいて、 会社でCの関数書いてるときにどうでもいいローカル変数(関数先で値を変えない)を 値渡しにするか、constつけてポインタ渡しにして渡すかで速度変わるのかなーとか ぼんやり考えていたから実際に試してみた。 (実験プログラムでは、関数の引数でポインタとしている仮引数にconstを付けていないが、 関数先で値を変わってくることを期待していない変数であればconstをつけたほうがよいと思います。)
実験1 関数内で渡した変数に何もしない
/* pointer-test_none.c */ #define TRIAL_COUNT 100000000 void numeric(int a); void pointer(int *a); int main(void) { int i, num = 1; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num); #else numeric(num); #endif } return 0; } void numeric(int i) { ; } void pointer(int *i) { ; }
実験1のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_none pointer-test_none.c # コンパイル time ./pointer-test_none # 実行 ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.29s user 0.00s system 99% cpu 0.291 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.292 total ./pointer-test_none 0.30s user 0.00s system 102% cpu 0.294 total gcc -w -Wall -o pointer-test_none pointer-test_none.c # コンパイル time ./pointer-test_none # 実行 ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.317 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.318 total ./pointer-test_none 0.32s user 0.00s system 100% cpu 0.317 total # 結果 値渡しのほうが、関数内で使う仮引数に値を一度コピーしているんだっけか、 速度がポインタ渡しのほうが速い結果となった。
実験2 関数内で渡した変数に10回アクセスする
/* pointer-test_sum.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a); void pointer(int *a); int main(void) { int i, num = 1; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num); #else numeric(num); #endif } return 0; } void numeric(int a) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += a; } } void pointer(int *a) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += *a; } }
実験2のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum pointer-test_sum.c # コンパイル time ./pointer-test_sum # 実行 ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total ./point-test_sum 2.57s user 0.00s system 100% cpu 2.570 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.558 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total ./point-test_sum 2.56s user 0.00s system 100% cpu 2.557 total gcc -w -Wall -o pointer-test_sum pointer-test_sum.c # コンパイル time ./pointer-test_sum # 実行 ./point-test_sum 2.44s user 0.00s system 100% cpu 2.438 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.432 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.432 total ./point-test_sum 2.42s user 0.01s system 99% cpu 2.431 total ./point-test_sum 2.44s user 0.00s system 100% cpu 2.434 total # 結果 ポインタ渡しをして、ポインタ介して変数の値をいちいち参照しているのか、 何度もアクセスすると、速度が値渡しのほうが速い結果となった。
実験3 関数内で渡した複数の変数に10回アクセスする
/* pointer-test_sum_many.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a, int b, int c); void pointer(int *a, int *b, int *c); int main(void) { int i, num1 = 1, num2 = 2, num3 = 3; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num1, &num2, &num3); #else numeric(num1, num2, num3); #endif } return 0; } void numeric(int a, int b, int c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (a + b + c); } } void pointer(int *a, int *b, int *c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (*a + *b + *c); } }
実験3のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル time ./pointer-test_sum_many # 実行 ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.208 total ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.206 total ./point-test_sum_many 3.21s user 0.00s system 100% cpu 3.208 total ./point-test_sum_many 3.21s user 0.00s system 99% cpu 3.211 total ./point-test_sum_many 3.20s user 0.02s system 100% cpu 3.214 total ./point-test_sum_many 3.15s user 0.08s system 100% cpu 3.226 total gcc -w -Wall -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル time ./pointer-test_sum_many # 実行 ./point-test_sum_many 2.68s user 0.02s system 100% cpu 2.696 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.699 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.693 total ./point-test_sum_many 2.69s user 0.01s system 100% cpu 2.698 total ./point-test_sum_many 2.70s user 0.00s system 100% cpu 2.696 total # 結果 コピーする仮引数の数が増えればとポインタ渡しのほうが速くなるかなと思ったが、 ポインタ介して変数の値を参照する回数のほうが今回の実験では影響大なためか 値渡しのほうが速い結果となった。
実験4 関数内で渡した複数の変数に10回アクセスする (ローカル変数に一度コピー)
本末転倒だが、ポインタで渡した変数の中身を、ローカル変数に一度コピーして 実験してみた。
/* pointer-test_sum_many2.c */ #define TRIAL_COUNT 100000000 #define ACCESS_COUNT 10 void numeric(int a, int b, int c); void pointer(int *a, int *b, int *c); int main(void) { int i, num1 = 1, num2 = 2, num3 = 3; for (i = 0; i < TRIAL_COUNT; i++) { #if defined(POINTER) pointer(&num1, &num2, &num3); #else numeric(num1, num2, num3); #endif } return 0; } void numeric(int a, int b, int c) { int i, sum = 0; for (i = 0; i < ACCESS_COUNT; i++) { sum += (a + b + c); } } void pointer(int *a, int *b, int *c) { int i, sum = 0; int aa = *a, bb = *b, cc = *c; /* <- koko!! */ for (i = 0; i < ACCESS_COUNT; i++) { sum += (aa + bb + cc); } }
実験4のコンパイル&結果
gcc -w -Wall -DPOINTER -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル time ./pointer-test_sum_many2 # 実行 ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.967 total ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.963 total ./point-test_sum_many2 2.97s user 0.00s system 100% cpu 2.964 total gcc -w -Wall -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル time ./pointer-test_sum_many2 # 実行 ./point-test_sum_many2 2.69s user 0.00s system 100% cpu 2.689 total ./point-test_sum_many2 2.70s user 0.00s system 100% cpu 2.692 total ./point-test_sum_many2 2.69s user 0.00s system 100% cpu 2.688 total # 結果 ポインタ介してアクセスする回数が減ったけども、ローカル変数に一度コピーする ことが影響しているのか、ただ値渡しにするよりもポインタ渡しのほうが遅い結果となった。
実験のまとめ
・関数内で引数で渡してきた変数の中身に何度もアクセスしないのであれば、 ポインタ渡しのほうが速い(仮引数を作りコピーする処理がないため) ※冒頭でも書きましたが、上記の場合はconstをつけたほうが見る人は、 「この変数は関数の先で変わってくることを期待していないんだな」とわかるので、 つけたほうがいいと思います。 ・逆に何度もアクセスするのであれば、値渡しにしてしまったほうが速い (ポインタ介して値を引っ張ってくるため(であってる?))
検索用タグ C言語 実行速度
2012/05/27 (Sun.) Comment(0) C言語