[英]A type for arbitrary memory in C
This is in reference to this question 这是参考这个问题
How to implement the c malloc/realloc functions properly? 如何正确实现c malloc / realloc函数?
where the accepted answer mentions that a char
array can be used to model a pool of arbitrary memory. 接受的答案提到可以使用char
数组对任意内存池进行建模。
However one of the comments to that accepted answer states 但是,对该已接受答案的评论之一指出
A char array that doesn't have allocated storage duration can only be aliased by a character type. 没有分配存储时间的char数组只能以字符类型作为别名。 In other words it cannot and it should not be used as arbitrary memory 换句话说,它不能也不应用作任意内存
Is this correct? 这个对吗? If so, then what could be used? 如果是这样,那么可以使用什么呢? I'd like to avoid using alloc
or any specific OS calls - so I'm symmetrical with that question. 我想避免使用alloc
或任何特定的OS调用-所以我对这个问题持对称态度。
There are different problems around. 周围有不同的问题。 First as shown by @Magisch's answer the related question was returning a dangling pointer causing Undefined Behaviour and generally execution errors. 首先,如@Magisch的答案所示,相关问题是返回一个悬空指针,导致未定义行为和一般执行错误。
The second one is related to the @^*# (censorship here) strict aliasing rule. 第二个与@ ^ *#(此处为检查)严格的别名规则相关。 Common compilers produce correct code when you use a character array as a large buffer to allocate any type from it, provided you ensure correct alignment. 当您将字符数组用作大缓冲区以从中分配任何类型时,如果您确保正确对齐,则普通编译器会生成正确的代码。 After all, this is the way they have to implement the malloc
, realloc
, and free
routines. 毕竟,这是他们必须实现malloc
, realloc
和free
例程的方式。 And as they are part of the hosted environment (C standard library), the compiler developpers are not masochist enough to fordib that usage. 而且,由于它们是托管环境 (C标准库)的一部分,因此编译器开发人员还不足以禁止其使用。
But the C standard is a bit more strict here. 但是C标准在这里更加严格。 You should read my own answer here to a similar question and particularly @EOF's comment to it: 您应该在此处阅读我对类似问题的答案,尤其是@EOF对它的评论:
You cannot parcel of parts of an object declared as char [] into objects of other types (except character types), because they do have a declared type... which means technically you can't implement malloc() in pure C 您不能将声明为char []的对象的一部分打包为其他类型(字符类型除外)的对象,因为它们确实具有声明的类型...这意味着从技术上讲,您不能在纯C语言中实现malloc()
Aliasing refers to the strict aliasing rule that governs how the compiler is allowed to use registers. 别名是指严格的别名规则 , 该规则控制如何允许编译器使用寄存器。 If you have pointers of different type referring to the same memory location, then writing done through one pointer type may not be noticed when reading through the other pointer type because the compiler is allowed to cache the data in registers. 如果您具有指向同一存储器位置的不同类型的指针,则在通过另一种指针类型进行读取时可能不会注意到通过一种指针类型完成的写入,因为允许编译器将数据缓存在寄存器中。
When you implement a memory pool, this problem is usually moot, because the pool implementation doesn't read/write to the memory. 当您实现一个内存池时,这个问题通常是没有解决的,因为该池实现不会对内存进行读/写操作。
If you want arbitrary types, then the safest bet is a union. 如果要使用任意类型,那么最安全的选择是联合。 Not only will it "beat" the strict aliasing rule, it will also ensure correct alignment. 它不仅会“击败”严格的别名规则,还将确保正确的对齐方式。 Remember that malloc
and friends ensure alignment suitable for any type while auto
doesn't. 请记住, malloc
和Friends确保适合任何类型的对齐方式,而auto
不适合。
The issue is alignment. 问题是对齐。 On processors that have alignment restrictions, a char
array may not start at an address suitable for storing larger objects, like int
or double
. 在具有对齐限制的处理器上, char
数组可能不会从适合于存储较大对象(例如int
或double
的地址开始。
So to be safe, you need to make sure the char
array is aligned properly for any type. 为了安全起见,您需要确保char
数组对于任何类型都正确对齐。 If you're using a C11 compiler, then you can force alignment like this 如果您使用的是C11编译器,则可以像这样强制对齐
#include <stddef.h>
#include <stdalign.h>
_Alignas(max_align_t) char buffer[SIZE];
For older compilers, __attribute__((aligned(SIZE)))
may be a solution. 对于较旧的编译器, __attribute__((aligned(SIZE)))
可能是一个解决方案。 Otherwise, you need to look for a #pragma
that forces alignment. 否则,您需要查找强制对齐的#pragma
。
And as discussed in various comments/answers, you should definitely disable the strict aliasing optimization with the -fno-strict-aliasing
option. 而且,正如在各种注释/答案中所讨论的,您绝对应该使用-fno-strict-aliasing
选项禁用严格的别名优化。 If that option (or the equivalent) doesn't exist, then you need to determine the optimization level that relies on the strict aliasing rule, and only use a lower optimization level. 如果该选项(或等效选项)不存在,则需要确定依赖于严格别名规则的优化级别,并且仅使用较低的优化级别。
I believe the issue he pointed out was that if you allocate a char
type array statically and then compile your library with a modern, desktop-like C compiler like gcc, you cannot easily convert the contents of that area to another type. 我认为他指出的问题是,如果您静态分配一个char
类型的数组,然后使用像gcc这样的现代,类似于桌面的C编译器来编译您的库,则无法轻松地将该区域的内容转换为另一种类型。 Because then the compiler would perform optimizations based on pointer aliasing and screw everything up, see "the strict aliasing rule" . 因为这样编译器将基于指针别名执行优化并将所有事情搞砸,因此请参阅“严格的别名规则” 。
Simply assure that your compiler does not use strict aliasing and you'll be fine. 只需确保您的编译器不使用严格的别名就可以了。 For example, none of the common embedded systems compilers on the market does this. 例如,市场上没有一个普通的嵌入式系统编译器可以做到这一点。
With gcc you'd compile as -fno-strict-aliasing
. 使用gcc时,您将编译为-fno-strict-aliasing
。 Might be good to always enable warnings for code that would cause such problems -Wstrict-aliasing
. 始终为可能导致此类问题的代码启用警告可能会很有用-Wstrict-aliasing
。
As a side note, uint8_t
makes far more sense to use as generic type, because unlike char
, it is completely unambiguous: it has no signedness and the size is well-known. 附带说明一下,将uint8_t
用作泛型类型更有意义,因为与char
不同,它是完全明确的:它没有签名,并且大小是众所周知的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.