字节对齐

近日在工作中遇到一个奇怪问题,A程序发送一个结构给B程序,在B程序接收后,B程序按照A程序的结构进行解析,但始终不对。看过结构定义后,虽然知道有可能会出现字节对齐问题,一直怀疑是他们消息传输构造不对。经过GDB确认A程序发出的结构是正确的,在B程序接收处也同样没问题。当调试到转化处时才发现确实是字节对齐导致的。下面举例说明(32bit Linux Gcc)。

server.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#pragma pack(1)
typedef struct
{
    unsigned int a;
    short int b;
    long long int c;
    unsigned int d;
} type1;
#pragma pack()

#define PORT  8888

int main(int argc, char *argv[])
{
    int    fd = 0;
    int    len = 0;    
    int    err = 0; 
    char  *buff = NULL;    
    char   recvbuf[1024]={0};
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    type1 *C = NULL;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        printf("Socket create failure");
        return -1;
    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);
    len = sizeof(struct sockaddr_in);

    err = bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (-1 == err)
    {
        printf("bind error\n");
        return -1;
    }

    while (1)
    {
        recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&client_addr, &len);
        C = (type1 *)recvbuf;
        printf("C={0x%x,0x%x,0x%llx,0x%x}\n", C->a, C->b, C->c, C->d);
    }

    return 0;
}

//输出
[root@smart Desktop]# ./server
C={0x11223344,0x5566,0x5678901234560019,0x43211234}

client.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>


#pragma pack(4)
typedef struct
{
    unsigned int a;
    short int b;
    long long int c;
    unsigned int d;
} type1;
#pragma pack()


#define PORT  8888

int main(int argc, char *argv[])
{
    int    fd = 0;
    int    len = 0;    
    int    err = 0; 
    char  *buff = NULL;    
    char   recvbuf[1024]={0};
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    type1  A = {0x11223344, 0x5566, 0x1234567890123456LL, 0x87654321};

    printf("sizeof(A)=%d,A={0x%x,0x%x,0x%llx,0x%x}\n", sizeof(A), A.a, A.b, A.c, A.d);

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        printf("Socket create failure");
        return -1;
    }

    buff = (char *)&A;

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);
    len = sizeof(struct sockaddr_in);

    sendto(fd, buff, sizeof(type1), 0, (struct sockaddr *)&server_addr, len);

    return 0;
}
//输出
[root@smart Desktop]# ./client
sizeof(A)=20,A={0x11223344,0x5566,0x1234567890123456,0x87654321}
[root@smart Desktop]# 

从上面这个示例可以看出,输出的结果与我们预期的不一样。这是因为在32位系统下,数据存储将按结构体成员的最大字节数对齐,并且最大字节数为4。 上面的用例采用了手工设置对齐方式来测试该问题。从上述的运行结果看,我们需要在两个程序间保持一致,最好手动设置一样的字节对齐方式。

pragma pack(1)表示按一字节对齐,#pragma pack()表示取消前面的字节对齐,按默认方式对齐。

另外在编码时我们就应该考虑结构设计,尽量避免会引入需要考虑字节对齐的问题,如将short int 改为int,就无需考虑该问题。

–质量高的代码会将问题消灭在编码阶段,修复bug将会让你效率更低。


Juyin@2017/1/14

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值