问题代码如下,当时我是想用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)。
相关推荐
static_cast:用于“良性”和“适度良性”的转换,包括不用强制转换 const_cast:用于“const”和/或“volatile”进行转换 reinterpret_cast:转换为完全不同的意思。为了安全的使用它,关键必须转换回原来的类型。...
显式转换需要强制转换运算符,而且强制转换会造成数据丢失。 下面的实例显示了一个显式的类型转换: namespace TypeConversionApplication { class ExplicitConversion { static void Main(string
但是,因为隐式转换不需要程序员将一种类型显式强制转换 为另一种类型,所以使用隐式转换时必须格外小心,以免出现意外结果。一般情况下,隐式转换运算符应当从不引发异常并且 从不丢失信息,以便可以在程序员不知晓...
TestB() 会在堆上 new 一个 NewB 的对象,但是会强制转换成 BaseA 类型的指针并返回(这个操作太逆天,大家一定不要在项目代码中这么玩儿)。main() 函数中模拟使用和释放。背景介绍完毕,看代码。 测试代码 1 #...
显式转换:也就是强制转换。告诉编译器,什么类型转换到什么类型。 二 隐式转换 小类型的数据可以自动转换为大类型的数据,具体看下表: 举个例子:想byte类型变成int类型: byte a=6; int b=a; 三 显式转换 接...
《你必须知道的495个C语言问题》结构清晰,讲解透彻,是各高校相关专业C语言课程很好的教学参考书,也是各层次C程序员的优秀实践指南。 -----------------------------------------------------------------------...
作者在网络版CFAQ列表的基础上进行了大幅度的扩充和丰富,结合代码示例,权威而且详细深入地解答了实际学习和工作中最常遇到的495个C语言问题,涵盖了初始化、数组、指针、字符串、内存分配、库函数、C预处理器等...
3.5 可否用显式括号来强制执行我所需要的计算顺序并控制相关的副作用?就算括号不行,操作符优先级是否能够控制计算顺序呢? 3.6 可是&&和||操作符呢?我看到过类似while((c=getchar())!=EOF&&c!='\n')的代码……...
什么是显式强制转换? 弦乐 16。 所有的String都是不可变的吗? 17。 字符串值存储在内存中的什么位置? 18。 为什么要在循环中注意String concatenation(+)运算符? 19。 您如何解决以上问题? 20。 Str
类型转换可以分为隐式转换和显式转换,所谓隐式转换即程序在运行时进行的自动转换,显式转换则是人为的对类型进行强制转换。Javascript的变量是松散类型的,它可以存储Javascript支持的任何数据类型,其变量的类型可以...
7.7.6 强制转换表达式 183 7.8 算术运算符 184 7.8.1 乘法运算符 184 7.8.2 除法运算符 185 7.8.3 余数运算符 186 7.8.4 加法运算符 187 7.8.5 减法运算符 189 7.9 移位运算符 190 7.10 关系和类型测试运算符 192 ...
7.7.6 强制转换表达式 183 7.8 算术运算符 184 7.8.1 乘法运算符 184 7.8.2 除法运算符 185 7.8.3 余数运算符 186 7.8.4 加法运算符 187 7.8.5 减法运算符 189 7.9 移位运算符 190 7.10 关系和类型测试运算符 192 ...
7.7.6 强制转换表达式 183 7.8 算术运算符 184 7.8.1 乘法运算符 184 7.8.2 除法运算符 185 7.8.3 余数运算符 186 7.8.4 加法运算符 187 7.8.5 减法运算符 189 7.9 移位运算符 190 7.10 关系和类型测试运算符 192 ...
7.7.6 强制转换表达式 183 7.8 算术运算符 184 7.8.1 乘法运算符 184 7.8.2 除法运算符 185 7.8.3 余数运算符 186 7.8.4 加法运算符 187 7.8.5 减法运算符 189 7.9 移位运算符 190 7.10 关系和类型测试运算符 192 ...
7.7.6 强制转换表达式 183 7.8 算术运算符 184 7.8.1 乘法运算符 184 7.8.2 除法运算符 185 7.8.3 余数运算符 186 7.8.4 加法运算符 187 7.8.5 减法运算符 189 7.9 移位运算符 190 7.10 关系和类型测试运算符 192 ...
对于指向数据成员的指针,结果将引用与指向数据成员的原始(未强制转换)的指针相同的成员。根据引用对象的类型,通过生成的指针、引用或指向数据成员的指针的写入操作可能产生未定义的行为。 您不能使用 const_cast...