Objective c 将基元或结构类型作为函数参数传递
我正在尝试编写一些相当通用的网络代码。我有几种类型的数据包,每个数据包由不同的结构表示。发生所有发送的函数如下所示:Objective c 将基元或结构类型作为函数参数传递,objective-c,pointers,struct,argument-passing,Objective C,Pointers,Struct,Argument Passing,我正在尝试编写一些相当通用的网络代码。我有几种类型的数据包,每个数据包由不同的结构表示。发生所有发送的函数如下所示: - (void)sendUpdatePacket:(MyPacketType)packet{ for(NSNetService *service in _services) for(NSData *address in [service addresses]) sendto(_socket, &packet, size
- (void)sendUpdatePacket:(MyPacketType)packet{
for(NSNetService *service in _services)
for(NSData *address in [service addresses])
sendto(_socket, &packet, sizeof(packet), 0, [address bytes], [address length]);
}
我真的希望能够发送这个函数的任何类型的数据包,而不仅仅是MyPacketType数据包
我想如果函数def是:
- (void)sendUpdatePacket:(void*)packetRef
我可以传递任何指向数据包的指针。但是,在不知道数据包类型的情况下,我无法取消对指针的引用
如何编写一个函数来接受任何类型的基元/结构作为其参数?您试图实现的是,这是一个面向对象的概念 <>这虽然在C++(或者其他OO语言)中很容易实现,但是在C.</P>中有点更具挑战性。 一种方法是创建一个通用的“数据包”结构,例如:
typedef struct {
void* messageHandler;
int messageLength;
int* messageData;
} packet;
其中,messageHandler
成员是指向可处理消息类型的回调例程的函数指针,messageLength
和messageData
成员完全是自解释的
其思想是,将packetStruct
传递给的方法将使用该原理调用特定的消息处理程序指针,通过messageHandler
,传入messageLength
和messageData
,而不进行解释
分派函数(由messageHandler
指向)将是特定于消息的,能够将messageData
转换为适当的有意义类型,然后可以从中提取并处理有意义的字段,等等
当然,C++在继承、虚拟方法等方面都更容易、更优雅。
编辑: 针对该评论: 我有点不清楚“如何”才能施展才华 将消息数据发送到相应的 有意义的类型,然后是 可以提取有意义的字段 从中提取并处理等 完成 您将为特定的消息类型实现一个处理程序,并将
messageHandler
成员设置为指向该处理程序的函数指针。例如:
void messageAlphaHandler(int messageLength, int* messageData)
{
MessageAlpha* myMessage = (MessageAlpha*)messageData;
// Can now use MessageAlpha members...
int messageField = myMessage->field1;
// etc...
}
您可以这样定义messageAlphaHandler()
,以允许任何类轻松获得指向它的函数指针。您可以在应用程序启动时执行此操作,以便从一开始就注册消息处理程序
请注意,要使此系统工作,所有消息处理程序都需要共享相同的函数签名(即返回类型和参数)
或者,就这一点而言,messageData
将首先创建
从我的结构
你是如何得到你的数据包的?您是手动创建它,还是从套接字读取它?无论哪种方式,您都需要将其编码为一个字节字符串。int*
成员(messageData
)只是指向编码数据开头的指针。messageLength
成员是此编码数据的长度
在消息处理程序回调中,您可能不希望继续将数据作为原始二进制/十六进制数据进行操作,而是根据消息类型以有意义的方式解释信息
将其强制转换为结构实质上是将原始二进制信息映射到一组有意义的属性,这些属性与您正在处理的消息的协议相匹配。关键是您必须认识到,计算机中的所有内容都只是一个字节数组(或、字或双字) 禅师芥末正坐在他的办公桌旁,盯着他的显示器,盯着一系列看似随机的复杂字符。一个学生走近了 学生:老师?我可以打断一下吗 芥末禅师:你已经回答了你自己的问题,我的儿子 S:什么 ZMM:通过问你关于打断我的问题,你打断了我 S:哦,对不起。我有一个问题是关于把不同大小的建筑物从一个地方移到另一个地方 ZMM:如果这是真的,那么你应该咨询一位擅长这些事情的大师。我建议你去拜访多普夫特大师,他对移动大型金属结构(如跟踪雷达)有着丰富的知识。多普夫特大师还可以使羽毛重量应变仪的最微小的元件随着鸽子的呼吸力而移动。向右转,到达hi bay的门口后向左转。那里住着多普夫特大师 S:不,我的意思是在计算机内存中移动不同大小的大型结构 ZMM:如果你愿意,我可以在这方面帮助你。描述你的问题 S:具体来说,我有一个c函数,我想接受几种不同类型的结构(它们将代表不同类型的数据包)。因此,我的结构数据包将作为void*传递给我的函数。但是不知道类型,我不能投他们,或者真的做很多事情。我知道这是一个可以解决的问题,因为socket.h中的sento()正是这样做的:
ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
其中sendto将被称为:
sendto(socketAddress, &myPacket, sizeof(myPacket), Other args....);
你向禅师曼塔描述过你的问题吗
S:是的,他说,“这只是一个指针。C语言中的所有东西都是指针。”当我要求他解释时,他说,“好吧,好吧,滚出我的办公室。”
真的,你已经和大师谈过了。这对你没有帮助吗
S:嗯,呃,没有。然后我问禅师马克斯
他很聪明。他的建议对你有用吗
S:没有。当我问他sendto()的事时,他只是挥舞着拳头。它只是一个字节数组。”
的确,禅师马克斯有头
S:是的,他有tau,但我如何处理void*类型的函数参数
ZMM:要学习,你必须首先忘却。关键是你必须意识到计算机中的一切都只是一个字节数组(或,单词,或doub)
char characterBuffer[300]; // 300 bytes
strcpy(characterBuffer, "You plan a tower that will pierce the clouds? Lay first the foundation of humility.");
// note that sizeof(characterBuffer) evaluates to 300 bytes.
sendto(socketAddress, &characterBuffer, sizeof(characterBuffer));
struct
{
int integerField; // 4 bytes
char characterField[300]; // 300 bytes
float floatField; // 4 bytes
} myStruct;
myStruct.integerField = 8765309;
strcpy(myStruct.characterField, "Jenny, I got your number.");
myStruct.floatField = 876.5309;
// sizeof(myStruct) evaluates to 4 + 300 + 4 = 308 bytes
sendto(socketAddress, &myStruct, sizeof(myStruct);
enum
{
INTEGER_IN_THE_PACKET =0 ,
STRING_IN_THE_PACKET =1,
STRUCT_IN_THE_PACKET=2
} typeBeingSent;
struct
{
typeBeingSent dataType;
char data[4096];
} Packet_struct;
Packet_struct myPacket;
myPacket.dataType = STRING_IN_THE_PACKET;
strcpy(myPacket.data, "Nothing great is ever achieved without much enduring.");
sendto(socketAddress, myPacket, sizeof(Packet_struct);
myPacket.dataType = STRUCT_IN_THE_PACKET;
memcpy(myPacket.data, (void*)&myStruct, sizeof(myStruct);
sendto(socketAddress, myPacket, sizeof(Packet_struct);
char[300] receivedString;
struct myStruct receivedStruct;
recvfrom(socketDescriptor, myPacket, sizeof(myPacket);
switch(myPacket.dataType)
{
case STRING_IN_THE_PACKET:
// note the cast of the void* data into type "character pointer"
&receivedString[0] = (char*)&myPacket.data;
printf("The string in the packet was \"%s\".\n", receivedString);
break;
case STRUCT_IN_THE_PACKET:
// note the case of the void* into type "pointer to myStruct"
memcpy(receivedStruct, (struct myStruct *)&myPacket.data, sizeof(receivedStruct));
break;
}