我正在开发一个处理C中某些网络连接的库,我的计划是让init函数返回一个结构,该结构包含连接的所有相关数据,然后调用方将这些数据传递给任何库函数。我还希望调用程序可以访问结构的内容。
这是我的init(库(代码
//here is the struct
typedef struct {
SSL_CTX* ctx;
SSL* ssl;
int socket;
int usingSSL;
} twitch_connection;
struct twitch_connection* twlibc_init(int usingSSL){ //returns a pointer to a struct that has to be freed
twitch_connection *temp;
temp = malloc(sizeof(twitch_connection)); //creates the address for the struct
struct sockaddr_in twitchaddr;
...
if(usingSSL == 0){
//not using SSL
temp->ctx = NULL;
temp->ssl = NULL;
}else {
//using SSL
temp->ctx = ctx; //how I assign values to the struct
temp->ssl = ssl;
}
temp->socket = twitchsock;
return temp; //returns the struct back to caller
}
这是我演示的代码
int main(){
twitch_connection* twlibc = twlibc_init(1);
printf("address of struct from main of callers code is: %pn", twlibc);
}
然而,当我打印结构的地址时,当从代码中的不同区域打印时,我会得到不同的结果:
address of struct from inside init function: 0x56299befd260
address of struct from main of callers code is: 0xffffffff9befd260
如果我试图从主函数打印结构的一个成员,我会得到一个分段错误。
twitch_connection* twlibc = twlibc_init(1);
由于此时未声明twlibc_init
,因此C假定返回值为int,因此上述内容等效于twlibc = (twitch_connection*)(int)twlibc_init(1);
。
在具有32位int
类型的64位平台上,这将把0x56299befd260
截断为32位整数0x9befd260
,然后将其符号扩展为64位指针0xffffffff9befd260
。
解决方案是在主文件中声明函数struct twitch_connection* twlibc_init(int usingSSL);
,或者更好的是,将声明移动到包含在两个位置的公共标头中。
[EDIT]将int
强制转换为指针时的符号扩展取决于实现,不受C标准的保证,因此另一个编译器可能打印了0x9befd260
,或者实际上打印了任何东西。从cppreference C cast操作符页面:
任何整数都可以强制转换为任何指针类型。除了null(不需要强制转换(等空指针常量外,结果是实现定义的,可能没有正确对齐,可能没有指向引用类型的对象,并且可能是陷阱表示