忍者ブログ

2024
05
03

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

2024/05/03 (Fri.)

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 安全

拍手[0回]

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言語 双方向リスト 自己参照型

拍手[0回]

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言語 可変長引数

拍手[0回]

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言語 プロセス間通信

拍手[0回]

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言語 実行速度

拍手[3回]

2012/05/27 (Sun.) Comment(0) C言語

ブログ内検索

最新記事

カテゴリー

アーカイブ

フリーエリア





プロフィール

HN:
nex2t
年齢:
8
性別:
男性
誕生日:
2016/01/01
職業:
開発エンジニア(ソフト)
趣味:
ラグビー 犬 将棋 ラーメン サーフィン(ネット)
自己紹介:
入社2年目の組込みエンジニア
好きな言語:C言語
エディタ:emacs
シェル:zsh
ディストリ:Scientific Linux, Ubuntu
略歴
お仕事のほう
2011/3 調布にある大学卒業
2011/4~6月 研修
2011/7~12月? 10GのLANドライバをがんばる
2012/1~2012/4月? VDCPデーモンを作る
2012/5~2012/10月? genlockデーモンを作る
~(現在) 装置テストなど

趣味などのほう
~2012年4月 自由気ままに。仕事の勉強など。歯医者に時間を取られる。
2012年4月~2012年6月 機動力が増す(バイクの免許&バイク(125ccの原付をゲットする)
2012年6月~2012年8月 将棋のネットゲームを作る(引きこもる)((こころざし半ば)
2012年7月~2012年8月 通勤途中にバイクでこけて('自損)、1か月チャリ通の刑になる
2012年9月~現在(2013年3月) DDRばかりする(主にDP)

(↑2013/3/10更新)

DDRのほう
------------------------------------------
・199?年 小学校高学年。
よく遊ぶ友達内でDDRが流行る。
3rdが家にあり、家庭用マットもあったが、ゲーセンでプレイすることは皆無。
(コロコロコミックとガブリチュウを買うと小遣いがなくなるぐらいしかお金がない)
Burtyfly、DAM DARIRAMとかの誰でも聞いたことあるような曲、DEAD END、Paranoia Rebirth、AFRONOVAとかちょっと難しい曲、
BUMBLE BEE、End of the Centuryとかいい感じで印象に残っている。
GRADIUSIC CYBERが当時意味不明で難しいなと思っていた。
ハンドクラップの他にもメトロノームとかついてた気がする。
スコアとかを気にしたことはなかった。
------------------------------------------
・199?年 中学。
4thを中古で購入。半年に1回ぐらいプレイしてた?(手でやるだけ)。
ワンダ・古畑・HERO・ピンクダイナソー・オリオン・DROP OUT(当時とても速かった)とかが印象に残っている。
---------------------------------------------
・200?年 高校。
MAXを中古で買って、たまにやっていた。ゲーセンに1クレだけ踏みに行ったりしてた。
SO DEEP、天ヒー、象さん、ウィッチドクター、トワイライトゾーン、MAX300が印象に残っている。
この頃、MAX300 SPのリズム(ダンダン ダダンダ(ry)が体に染みついた模様笑。
なおMAXは友人に貸したままの模様。
------------------------------------------
・200?年 大学。
数か月に1回、ストレス発散がてら踏んでいた。確かXとかX2だった気がする。
踏むのは決まって8分でけっこう踏んだ気になる、AFRONOVA、天ヒー、象さん。
Aランクとか出せたことがなかった。
---------------------------------------------
・2012年9月 社会人 X3
コミケ準備のため引きこもっていた反動で、外出ばかりする。
ゲーセンで久々にプレイするととても楽しい(画面もきれいでパネルの反応も良い)。
今まで適当にやってきたが、少しシステムとかスコアを気にし始める。
自分のお金ということもあり、ゲーセンで千円単位でお金を使うことが自然になり、
真面目にDDRをするようになる。
------------------------------------------
・2012年12月 X3
SPしかやったことがなかったが、当時よく通ったゲーセンがDPする人が多く、
楽しそうだったので、DPをやり始める、足の裏の皮がむける。
---------------------------------------------
・2013年4月? X3終了。 DDR2013へ
X3はSP足鳳凰、DP足龍で終了。DPは足12以下の好きな曲のみフルコンができるような具合だった。
------------------------------------------
・2013年7月 ついったーで記録をつけるようになる。
8月4日 足10以下の激譜面AA埋め達成。鬼鯖初クリア
8月10日 足11以下の激譜面AA埋め達成。
8月24日 DDR2013 1000クレ行く。
9月8日 足12以下の激譜面AA埋め達成。
10月   (私用でドタバタする。)
11月2日 Skill pointが1000行く。
11月3日 岐阜のDDR大会 DPノンバー部門参加(予選通過ならず)
11月16日 DP足鳳凰。(エレクリDDPフルコン)
11月22日 足13以下の激譜面AA埋め達成。
11月24日 DP足紙さま?。(苺プリンDDPフルコン、鬼鯖810k同時だった)
Double AA Line 14になる。
現在~  足14のAA埋め、足15のA取得、足13の鳥取りを頑張り中。
------------------------------------------
(↑2013/11/28追加)

最新CM

[06/01 履歴書の書き方]

カウンター