将数组复制到结构中

1 c memory arrays structure copying

我有一个9字节的数组,我想将这些字节复制到一个结构:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct _structure {
    char one[5];        /* 5 bytes */
    unsigned int two;   /* 4 bytes */
} structure;

int main(int argc, char **argv) {

    structure my_structure;

    char array[]    = {
        0x41, 0x42, 0x43, 0x44, 0x00,   /* ABCD\0 */
        0x00, 0xbc, 0x61, 0x4e          /* 12345678 (base 10) */
    };

    memcpy(&my_structure, array, sizeof(my_structure));

    printf("%s\n", my_structure.one);   /* OK, "ABCD" */
    printf("%d\n", my_structure.two);   /* it prints 1128415566 */

    return(0);
}
Run Code Online (Sandbox Code Playgroud)

该结构的第一元件my_structure,one被正确地复制; 但是,my_structure.two包含1128415566,而我期望12345678. array并且my_structure具有不同的大小,即使它们的大小相等,仍然会有问题two.我该如何解决这个问题?

2.7*_*718 5

有一些问题:

出于效率原因,编译器边界上的变量对齐等于处理器的寄存器大小.即在32位系统上,这将是32位(4字节)边界.此外,结构将具有"间隙",以便结构成员可以在32位边界上对齐.换句话说:结构不是紧密" 打包 "的.试试这个:

#include <stdio.h>

typedef struct
{
    char one[5];        /* 5 bytes */
    unsigned int two;   /* 4 bytes */
}
    structure;
structure my_structure;

char array[] = 
{
    0x41, 0x42, 0x43, 0x44, 0x00,   /* ABCD\0 */
    0x00, 0xbc, 0x61, 0x4e          /* 12345678 (base 10) */
};

int main(int argc, char **argv) 
{
    const int sizeStruct = sizeof(structure);
    printf("sizeof(structure) = %d bytes\n", sizeStruct);
    const int sizeArray = sizeof(array);
    printf("sizeof(array) = %d bytes\n", sizeArray);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

你应该看到不同的尺寸.

您可以使用#pragma或attribute指令覆盖此行为.使用gcc,您可以使用属性更改结构定义.例如,更改上面的代码以添加"packed"属性(需要gcc):

typedef struct __attribute__((packed))
Run Code Online (Sandbox Code Playgroud)

然后再次运行程序.尺寸现在应该是相同的. 注意:在某些处理器体系结构(例如ARMv4)上,32位变量必须在32位boudary上对齐,否则程序将无法运行(获得异常).阅读"对齐"和"打包"编译指示或属性的编译器文档.

下一个问题是字节顺序.试试这个:

printf("0x%08X\n", 12345678);
Run Code Online (Sandbox Code Playgroud)

十六进制的12345678是0x00BC614E.从你的例子和你得到的输出,我可以告诉你,你的平台是"小端".在"小端"系统中,该数字0x00BC614E被存储为以最低有效字节开始的字节序列,例如0x4E, 0x61, 0xBC, 0x00.所以改变你的数组定义:

char array[] = 
{
    0x41, 0x42, 0x43, 0x44, 0x00,   /* ABCD\0 */
    0x4E, 0x61, 0xBC, 0x00,         /* 12345678 (base 10) */
};
Run Code Online (Sandbox Code Playgroud)

现在你的程序将打印12345678.

另请注意,您应该使用%u来打印unsigned int.

复制char字符串可能是一堆蠕虫,特别是如果你必须允许不同的编码(例如Unicode).至少,您需要确保复制目标缓冲区免受溢出.

修改后的代码:

#include <stdio.h>
#include <string.h>

typedef struct
{
    char one[5];        /* 5 bytes */
    unsigned int two;   /* 4 bytes */
}
    structure;

structure my_structure;

char array[] = 
{
    0x41, 0x42, 0x43, 0x44, 0x00,   /* ABCD\0 */
    0x4E, 0x61, 0xBC, 0x00,         /* 12345678 (base 10) */
};

int main() 
{
    // copy string as a byte array
    memcpy(&my_structure.one, &array[0], sizeof(my_structure.one));

    // copy uint
    my_structure.two = *((unsigned int *)(&array[5]));

    printf("%s\n", my_structure.one);
    printf("%u\n", my_structure.two);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

最后,依赖打包数据结构通常是一个坏主意,因为它使得将代码移植到不同的平台变得困难.但是,有时您需要打包/解包协议包.在这些特殊情况下,对于每种数据类型,使用一对函数手动打包/解压缩每个项目通常是最好和最便携的.

我将留下关于另一个主题的endian-ness问题.:-)