C 分配给结构字段时,无符号短值会更改值

C 分配给结构字段时,无符号短值会更改值,c,struct,short,C,Struct,Short,我有一个解析20字节长的IP头缓冲区的函数: void parseIp(struct ipHeader *ip, const void *buffer) { uint8_t* b = buffer; // memcpy(b,buffer,20); ip->version = (b[0] & 0xf0) >> 4; ip->ihl = (b[0] & 0x0f); ip->dscp = (b[1] & 0x

我有一个解析20字节长的IP头缓冲区的函数:

void parseIp(struct ipHeader *ip, const void *buffer)
{
    uint8_t* b = buffer;
   // memcpy(b,buffer,20);
    ip->version = (b[0] & 0xf0) >> 4;
    ip->ihl = (b[0] & 0x0f);
    ip->dscp = (b[1] & 0xfC)>>2;
    ip->ecn = (b[1] & 0x3);

    unsigned short l = (b[2] << 8) | b[3];

    printf("%d\n",l);
    ip->length = l;
    ip->identification = (b[4] << 0xFF) | b[5];
}
现在代码将l打印为467,这是正确的,但由于该l被指定给struct字段长度,它将更改为54017。我完全不明白发生了什么事。我添加了变量l以确保不会发生溢出或类型转换错误,但它仍然会更改

这是学校工作的一部分,所以我不能改变结构

编辑 完整代码:

#include <stdio.h>
#include <arpa/inet.h>
#include "ipheader.h"


/* Parses the given buffer into an IP header structure.
 * 
 * Parameters:
 * ip: pointer to the IP header structure that will be filled based
 *      on the data in the buffer
 * buffer: buffer of 20 bytes that contain the IP header. */
    void parseIp(struct ipHeader *ip, const void *buffer)
    {
        uint8_t* b = buffer;
       // memcpy(b,buffer,20);
        ip->version = (b[0] & 0xf0) >> 4;
        ip->ihl = (b[0] & 0x0f);
        ip->dscp = (b[1] & 0xfC)>>2;
        ip->ecn = (b[1] & 0x3);

        unsigned short l = (b[2] << 8) | b[3];

        printf("%d\n",l);
        ip->length = l;
        ip->identification = (b[4] << 8) | b[5];
    }


/* Builds a 20-byte byte stream based on the given IP header structure
 * 
 * Parameters:
 * buffer: pointer to the 20-byte buffer to which the header is constructed
 * ip: IP header structure that will be packed to the buffer */
void sendIp(void *buffer, const struct ipHeader *ip)
{
}


/* Prints the given IP header structure */
void printIp(const struct ipHeader *ip)
{
    /* Note: ntohs below is for converting numbers from network byte order
     to host byte order. You can ignore them for now
     To be discussed further in Network Programming course... */
    printf("version: %d   ihl: %d   dscp: %d   ecn: %d\n",
            ip->version, ip->ihl, ip->dscp, ip->ecn);
    printf("length: %d   id: %d   flags: %d   offset: %d\n",
            ntohs(ip->length), ntohs(ip->identification), ip->flags, ip->fragment_offset);
    printf("time to live: %d   protocol: %d   checksum: 0x%04x\n",
            ip->time_to_live, ip->protocol, ntohs(ip->header_checksum));
    printf("source ip: %d.%d.%d.%d\n", ip->source_ip[0], ip->source_ip[1],
            ip->source_ip[2], ip->source_ip[3]);
    printf("destination ip: %d.%d.%d.%d\n", ip->destination_ip[0],
            ip->destination_ip[1],
            ip->destination_ip[2], ip->destination_ip[3]);    
}

/* Shows hexdump of given data buffer */
void hexdump(const void *buffer, unsigned int length)
{
    const unsigned char *cbuf = buffer;
    unsigned int i;
    for (i = 0; i < length; ) {
        printf("%02x ", cbuf[i]);
        i++;
        if (!(i % 8))
            printf("\n");
    }
}

struct ipHeader {
    int version;
    int ihl;
    int dscp;
    int ecn;
    unsigned short length;
    unsigned short identification;
    int flags;
    int fragment_offset;
    int time_to_live;
    int protocol;
    unsigned short header_checksum;
    unsigned char source_ip[4];
    unsigned char destination_ip[4];
};

void parseIp(struct ipHeader *ip, const void *buffer);
void sendIp(void *buffer, const struct ipHeader *ip);

void printIp(const struct ipHeader *ip);
void hexdump(const void *buffer, unsigned int length);


#include <arpa/inet.h>
#include "ipheader.h"

int main()
{
    /* Feel free to modify this function to test different things */

    unsigned char bytes[] = {
        0x45, 0x00, 0x01, 0xd3, 0xda, 0x8d, 0x40, 0x00,
        0x40, 0x06, 0x8c, 0xd5, 0xc0, 0xa8, 0x01, 0x46,
        0x6c, 0xa0, 0xa3, 0x33 };

    struct ipHeader ip;

    parseIp(&ip, bytes);
    printIp(&ip);

    struct ipHeader ipfields = {
        4, // version
        28, // ihl
        4, // dscp
        0, // ecn
        htons(1500), // length
        htons(1234), // id
        1, // flags
        1024, // offset
        15, // time_to_live
        33, // protocol
        htons(0x1234), // checksum (invalid)
        {1, 2, 3, 4}, // source IP
        {5, 6, 7, 8} // destination IP
    };
    unsigned char sendbuf[20];

    sendIp(sendbuf, &ipfields);
    hexdump(sendbuf, sizeof(sendbuf));
}
#包括
#包括
#包括“ipheader.h”
/*将给定缓冲区解析为IP头结构。
* 
*参数:
*ip:指向将基于填充的ip头结构的指针
*关于缓冲区中的数据
*缓冲区:包含IP头的20字节缓冲区*/
void parseIp(结构ipHeader*ip,常量void*buffer)
{
uint8_t*b=缓冲区;
//memcpy(b,缓冲器,20);
ip->version=(b[0]&0xf0)>>4;
ip->ihl=(b[0]&0x0f);
ip->dscp=(b[1]&0xfC)>>2;
ip->ecn=(b[1]&0x3);
无符号短l=(b[2]长度=l;
ip->identification=(b[4]版本,ip->ihl,ip->dscp,ip->ecn);
printf(“长度:%d id:%d标志:%d偏移量:%d\n”,
ntohs(ip->长度)、ntohs(ip->标识)、ip->标志、ip->碎片偏移);
printf(“生存时间:%d协议:%d校验和:0x%04x\n”,
ip->time_to_live,ip->protocol,ntohs(ip->header_checksum));
printf(“源ip:%d.%d.%d.%d\n”,ip->source\u ip[0],ip->source\u ip[1],
ip->source_ip[2],ip->source_ip[3];
printf(“目标ip:%d.%d.%d.%d\n”,ip->目标ip[0],
ip->目的地ip[1],
ip->目的地ip[2],ip->目的地ip[3];
}
/*显示给定数据缓冲区的hextump*/
void hextump(常量void*缓冲区,无符号整数长度)
{
const unsigned char*cbuf=缓冲区;
无符号整数i;
对于(i=0;i
不确定您是否知道endian(大端/小端) 参考:

基本上,一个小的endian格式颠倒顺序,将最低有效字节存储在较低的内存地址,最高有效字节存储在最高的内存地址

因此,当您分配I(467=0x1d3)时,它将根据您的机器端度(0xd301=54017)以小端格式存储


因此,如果您希望指定正确的值,请使用htons。

不确定您是否知道endian(大端/小端) 参考:

基本上,一个小的endian格式颠倒顺序,将最低有效字节存储在较低的内存地址,最高有效字节存储在最高的内存地址

因此,当您分配I(467=0x1d3)时,它将根据您的机器端度(0xd301=54017)以小端格式存储


因此,如果您希望分配正确的值,请使用htons。

正如其他人所提到的,您可能会遇到一些移位问题,因为您的移位超出了数据类型的宽度,这会导致..?(我不知道,似乎有一个关于是否定义了此行为的争论).幸运的是,在我的机器上,您的代码生成了467,这是正确的。但是,强制转换解引用明确定义了您想要的内容

 unsigned short l = (((unsigned short)b[2]) << 8) | ((unsigned short)b[3]);
注意,当您将
b
强制转换为不同的指针类型时,索引会发生变化


如果我完全控制了结构,我会使用位字段创建整个结构,那么你就不必担心移位,但是你说结构是为你定义的。

正如其他人所提到的,看起来你可能有一些移位问题,因为你移位的宽度超出了数据类型的宽度,而h导致..?(我不知道,似乎有一个关于这是否是定义的行为的争论)。幸运的是,在我的机器上,您的代码导致467,这是正确的。但是,强制取消引用显式定义了您想要的

 unsigned short l = (((unsigned short)b[2]) << 8) | ((unsigned short)b[3]);
注意,当您将
b
强制转换为不同的指针类型时,索引会发生变化

如果我完全控制了结构,我会使用位字段创建整个结构,那么您根本不必担心移位,但您说结构是为您定义的。

对于给定的输入:

unsigned char bytes[] = { 0x45, 0x00, 0x01, 0xd3, 0xda, 
然后代码:

unsigned short l = (b[2] << 8) | b[3];
您仍将看到
467


我猜您提到的问题是
printIp
函数打印
unsigned short l = (b[2] << 8) | b[3];
printf("%d\n", ip->length);