我正在寻找一种更短/更优雅的方式来从收到的NTP数据包中获取NTP时间戳。数据包存储在一个unsigned char数组buf中,来自socket函数recvfrom:
unsigned char buf[48];
recvfrom(sockfd, buf, 48, 0, (struct sockaddr *) &their_addr, &addr_len));
然后我将表示32位时间戳秒的40-43rd元素的值复制到无符号长整数transSec中,其位移类似如下:
recvPacket->transmitSec = buf[40];
recvPacket->transSec <<= 8;
recvPacket->transSec |= buf[41];
recvPacket->transSec <<= 8;
recvPacket->transSec |= buf[42];
recvPacket->transSec <<= 8;
recvPacket->transSec |= buf[43];
这种方法很好,但为了学习,是否有更短/更优雅的方式?我试过memcpy:
memcpy(&recvPacket->transSec, &buf[40], sizeof(unsigned long));
以上的其他一些变体,但我得到的数字不正确。我并不是特别自信我正确使用它。
答案 0 :(得分:3)
实际上这可能是 endianness 问题。在这里查看wiki条目:http://en.wikipedia.org/wiki/Endianness。简而言之,从一个系统到另一个系统,类型的字节排序不一定相同。您似乎正在进行网络通信 - 请查看字节顺序转换系列函数:
http://beej.us/guide/bgnet/output/html/multipage/htonsman.html
请注意,buf [40]是流中的第一个字节,并且一直移位到基础类型的最高字节。另一方面,memcpy会将buf [40]复制到transSec的0偏移量中 - 在两个例子中,字节顺序实际上是相反的。
您可以在这样的代码中查看它,您将声明一个字符指针(字符是c中最小的可寻址类型),并从您的地址中走出类型大小的长度。重新检查地址+ sizeof(类型):
// declare a char *
char * walker;
// set it to your integer
walker = (char *)&(recvPacket->transSec);
for ( i = 0; i < sizeof(unsigned long); i++){
// print out the bytes from memory address[0] - address[3] ( assuming 4-byte unsigned long)
printf("%x\n", walker[i]);
}
你也可以像这样走路buff,但那已经是一个char缓冲区所以,你也可以打印它。我认为您会看到字节顺序颠倒过来。