简体   繁体   English

替代嵌入式C ++中的零大小数组

[英]Alternative to zero-sized array in embedded C++

The Multiboot Specification has structures like this: 多引导规范具有以下结构:

struct multiboot_tag_mmap
{
  multiboot_uint32_t type;
  multiboot_uint32_t size;
  multiboot_uint32_t entry_size;
  multiboot_uint32_t entry_version;
  struct multiboot_mmap_entry entries[0];  
};

The intent seems to be that the array size can vary. 意图似乎是数组大小可能会有所不同。 The information is not known until passed along by the boot loader. 在引导加载程序传递之前,不知道该信息。 In hosted C++, the suggested advice is to "use vector ". 在托管C ++中,建议的建议是“使用vector ”。 Well, I can't do that. 好吧,我做不到。 The alternative is to use dynamic allocation, but that would require implementing a significant chunk of the kernel (paging, MMU, etc.) before I even have the memory map information. 另一种方法是使用动态分配,但这需要在我拥有内存映射信息之前实现内核的重要部分(分页,MMU等)。 A bit of a chicken or egg problem. 有点鸡肉或鸡蛋的问题。

The "hack" is to just enable extensions with gnu++11 . “hack”只是使用gnu++11启用扩展。 But I try to avoid using extensions as much as possible to avoid C-ish code or code that could potentially lead to undefined behavior. 但我尽量避免使用扩展,以避免可能导致未定义行为的C-ish代码或代码。 The more portable the code is, the less chance of bugs in my opinion. 代码越便携,我认为错误的可能性就越小。

Finally, you iterate over the memory map like this: 最后,你像这样迭代内存映射:

for (mmap = ((struct multiboot_tag_mmap *) tag)->entries;
    (multiboot_uint8_t *) mmap
    < (multiboot_uint8_t *) tag + tag->size;
    mmap = (multiboot_memory_map_t *)
    ((unsigned long) mmap
    + ((struct multiboot_tag_mmap *) tag)->entry_size))

So the size of the structure is tag->size . 所以结构的大小是tag->size

I can modify the multiboot header so long as the semantics are the same. 只要语义相同,我就可以修改多引导头。 The point is how it looks to the bootloader. 关键在于它对引导加载程序的看法。 What can I do? 我能做什么?

Instead of 0-sized array, you can use 1-sized array: 您可以使用1个大小的数组,而不是0大小的数组:

struct multiboot_tag_mmap
{
    ...
    struct multiboot_mmap_entry entries[1]; 
};

This will change only result of sizeof(struct multiboot_tag_mmap) , but it shouldn't be used in any case: size of allocated structure should be computed as 这将仅更改sizeof(struct multiboot_tag_mmap) ,但不应在任何情况下使用:已分配结构的大小应计算为

offsetof(struct multiboot_tag_mmap, entries) + <num-of-entries> * sizeof(struct multiboot_mmap_entry)

Alignment of the map structure doesn't depends on the number of elements in the entries array, but on the entry type . 映射结构的对齐不依赖于条目数组中的元素 ,而是取决于条目类型

Strictly confirming alternative : If there is known bounary for array size, one can use this boundary for type declaration: 严格确认替代方法 :如果数组大小已知有边界,可以使用此边界进行类型声明:

struct multiboot_tag_mmap
{
    ...
    struct multiboot_mmap_entry entries[<UPPER-BOUNDARY>]; 
};

For such declaration all possible issues described below are not applied. 对于此类声明,不适用下面描述的所有可能的问题。

NOTE about elements accessing: For accessing elements (above the first one) in such flexible array one need to declare new pointer variable: 关于访问元素的注释:为了访问这种灵活数组中的元素(在第一个元素之上),需要声明新的指针变量:

struct multiboot_mmap_entry* entries = tag->entries;
entries[index] = ...; // This is OK.

instead of using entries field directly: 而不是直接使用entries字段:

tag->entries[index] = ...; // WRONG! May spuriously fail!

The thing is that compiler, knowing that the only one element exists in the entries field array, may optimize last case it to: 问题在于,编译器知道entries字段数组中只存在一个元素,可以优化它的最后一种情况:

tag->entries[0] = ...; // Compiler is in its rights to assume index to have the only allowed value

Issues about standard confirmance : With flexible array approach, there is no object of type struct multiboot_tag_mmap in the memory(in the heap or on the stack). 关于标准验证的问题 :使用灵活的数组方法,内存中(堆中或堆栈中) 没有类型为struct multiboot_tag_mmap 对象 All we have is a pointer of this type, which is never dereferenced (eg for making full copy of the object). 我们所有的都是这种类型的指针 ,它永远不会被解引用 (例如,用于制作对象的完整副本)。 Similarly, there is no object of the array type struct multiboot_mmap_entry[1] , corresponded to the entries field of the structure, this field is used only for conversion to generic pointer of type struct multiboot_mmap_entry* . 同样, 没有数组类型struct multiboot_mmap_entry[1] ,对应于结构的entries字段,该字段仅用于转换为struct multiboot_mmap_entry*类型的泛型指针。

So, phrase in the C standard, which denotes Undefine Behavior 所以,C标准中的短语,表示Undefine Behavior

An object is assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type 将对象分配给不完全重叠的对象或具有不兼容类型的完全重叠的对象

is inapplicable for accessing entries array field using generic pointer: there is no overlapping object here. 不适用于使用通用指针访问entries数组字段:此处没有重叠对象

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM