C显式强制转换问题

问题代码如下,当时我是想用libevent在win32上监听一个端口的输入。

 

 

/*
 * Compile with:
 * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
 * see
 * http://d.hatena.ne.jp/mtaneda/20090302/1235998584
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#else
#include <winsock.h>
#include <windows.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event.h>

static void read_handler(int fd, short event, void *arg)
{
	char buf[256] = {0};
	struct event *ev;
	
	ZeroMemory(buf, sizeof(buf));
	ev = (struct event*)arg;
	if(event & EV_READ)
	{
		if(recv(fd, buf, sizeof(buf), 0)<=0)
		{
			event_del(ev);
			free(ev);
			closesocket(fd);
		}
		else
		{
			printf("[read_handler] read=%s\n", buf);
		}
	}
}

static void accept_handler(int fd, short event, void *arg)
{
	struct sockaddr_in addr;
	struct event *new_ev;
	int new_fd;
	int addrlen;
	
	addrlen = sizeof(addr);
	if(event & EV_READ)
	{
		printf("[accept_handler]\n");
		new_fd = accept(fd, (struct sockaddr*)&addr, &addrlen);
		new_ev = malloc(sizeof(struct event));
		event_set(new_ev, new_fd, EV_READ|EV_PERSIST, read_handler, new_ev);
		event_add(new_ev, NULL);
	}
}

int main (int argc, char **argv)
{
	struct event ev;
	SOCKET sock;
	int on;
	int rc;
	struct sockaddr_in addr;
	int server_port = 8888;
	
	WORD version = MAKEWORD (1,1);
	WSADATA wsadata;
	WSAStartup (version, &wsadata);
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
		perror("socket() failed");
		WSACleanup();
		exit(-1);
	}
	rc = setsockopt(sock, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on));
	if (rc < 0)
	{
		perror("setsockopt() failed");
		closesocket(sock);
		WSACleanup();
		exit(-1);
	}
	rc = ioctlsocket(sock, FIONBIO, &on);
	if (rc < 0)
	{
		perror("ioctl() failed");
		closesocket(sock);
		WSACleanup();
		exit(-1);
	}
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(server_port);
	rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
	if (rc < 0) 
	{
		perror("bind() failed");
		closesocket(sock);
		WSACleanup();
		exit(-1);
	}
	rc = listen(sock, 32);
	if (rc < 0)
	{
		perror("listen() failed");
		closesocket(sock);
		WSACleanup();
		exit(-1);
	}

	event_init();
	event_set(&ev, (int)socket, EV_READ | EV_PERSIST, accept_handler, &ev);
	event_add(&ev, NULL);
	
	event_dispatch();
	
	closesocket(sock);
	WSACleanup();
	return (0);
}

 

这个程序并没有在event_dispatch()处进入监听状态,而是在main函数最后的return (0);处退出,

后来发现bug其实在这里

 

 

	event_init();
	event_set(&ev, (int)socket, EV_READ | EV_PERSIST, accept_handler, &ev);
	event_add(&ev, NULL);

 

 我在重命名socket对象的名称时忘记改这里。

结果代码把socket这个函数显式地转换为int型,

当时以为强制转换是必须,但事实上不是。

libevent在运行时也没有发现这个问题,于是直接退出event_dispatch()循环。

正确的写法是

 

 

	event_init();
	event_set(&ev, sock, EV_READ | EV_PERSIST, accept_handler, &ev);
	event_add(&ev, NULL);

 

结论是:

C代码中任何显式和隐式的类型转换都需要加倍小心,尤其是在重构代码更改变量名的时候。

尽量避免类型转换,不要完全依赖某个特定的C编译器的检查(这里我使用的是VC2008)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值