/* Sockets.c */ typedef ssize_t (*SocketOp)(int fd, void *Msg, size_t MsgLen, void *Argu); struct Socket { int fd; void *Argu; SocketOp ReadCB; SocketOp WriteCB; } ssize_t SocketRead(struct Socket *pSock, void *Msg, size_t MsgLen) { return pSock->ReadCB(pSock->fd, Msg, MsgLen, pSock->Argu); }And several implements:
/* Socket_NonBlocking.c */ ssize_t NBReadCB(int fd, void *Msg, size_t MsgLen, void *Argu) { return recv(fd, Msg, MsgLen, MSG_DONTWAIT); } ssize_t NBWriteCB(int fd, void *Msg, size_t MsgLen, void *Argu) { return send(fd, Msg, MsgLen, MSG_DONTWAIT); }
/* Socket_NonConnect.c */ ssize_t NCReadCB(int fd, void *Msg, size_t MsgLen, void *Argu) { struct sockaddr *Addr = (struct sockaddr *)Argu; return recvfrom(fd, Msg, MsgLen, 0, Addr, sizeof(struct sockaddr)); } ssize_t NCWriteCB(int fd, void *Msg, size_t MsgLen, void *Argu) { struct sockaddr *Addr = (struct spckaddr *)Argu; return recvfrom(fd, Msg, MsgLen, 0, Addr, sizeof(struct sockaddr)); }Here the callbacks NBReadCB, NBWriteCB, NCReadCB and NCWriteCB are expected to only be assigned to the pointers in Sockets.c, instead of being directly called in any position with any reason. Then the dilemma comes for whether setting these callbacks static or not: if it is not, then there should be an corresponding header files claims the proto type of these callbacks and be included by Socket.c, which makes it possible to be called directly for every one who include the header; on the other hand, if they are set to static, they could be called only within the file, which implies the callbacks are going messed up with the interfaces: Sockets.c, in a same big file.
Pattern of solutions is combining both the interfaces and implementations into one file, only when it is going to compile. For example, including all the implements source files, say:
#include "Sockets_NonBlocking.c" #include "Sockets_NonConnect.c",which have been set to static, in the main part/interface part. Note that it should only be done if it is sure to the only unique instances of the whole system. One other similar way is a script to doing the combination before compiling, such as amalgamation in SQLite.
A different solution has been seen to prevent the dilemma would be use the specific #define in the interface source file and checking by #ifdef in every implements, to set the limitations of the implements header includers, which looks like:
/* Sockets.c */ #define __SOCKET_INNER_ #include "Socket_NonBlocking.h"
/* Sockets_NonBlocking.h */ #ifndef __SOCKET_INNER_ /* Any way makes compiler yell... */ #else ssize_t NBReadCB(int fd, void *Msg, size_t MsgLen, void *Argu); ssize_t NBWriteCB(int fd, void *Msg, size_t MsgLen, void *Argu); #endif
to prevent someone include Socket_NonBlocking.h directly and not be expected to, although a blind define adding could break this. Also defect comparing with previous ways is symbol of these callbacks will be listed and exposed, which might causes huge differences in size and performance if it is compiled to be a library. The including method is better choice so far in my opinion.
沒有留言:
張貼留言