C/C++:如何在运行时检查数组是静态的还是动态的
C/C++: How to check if an array is static or dynamic during runtime
我想知道如何检查数组是静态分配的还是动态分配的。我在网上查了一下 mysql source code 中的实现,不知道为什么? (第 0303 行检查数组是否为静态)
/*
0301 Just mark as empty if we are using a static buffer
0302 */
0303 if (array->buffer == (uchar *)(array + 1))
0304 array->elements= 0;
这是DYNAMIC_ARRAY在mysql中的定义:
341
342 typedef struct st_dynamic_array
343 {
344 uchar *buffer;
345 uint elements,max_element;
346 uint alloc_increment;
347 uint size_of_element;
348 } DYNAMIC_ARRAY;
你不能。
您在这里缺少一些上下文。 在这种特殊情况下,已知 array->buffer
指向 (uchar*)(array + 1)
并且是静态分配的, 或 它指向某处else 并且是动态分配的。
但是 (uchar*)(array + 1)
并没有自动意味着某些东西是静态分配的。
这就像问这个函数如何找到数组的长度(即它不会,除非数组以0结尾):
int getArrayLength(int *a)
{
for(int i = 0; ; i++)
if(a[i] == 0)
return i + 1;
}
你不能 - 没有额外的信息。
对于C,数组就是一堆内存地址。 a[n]
其实就是(type(a))*((void*)&a+n*sizeof(a))
。它根本不关心它是如何(或是否)分配的,甚至地址是否真实。
附加信息可能是:
- 该变量属于特定类型,其中包含您可以检查所需信息的字段
- 这是你的情况:你提供的代码 "knows" 变量是
DYNAMIC_ARRAY
- 从分配系统获取提示
- 例如
free
和 realloc
只能用之前由 malloc
给出的指针调用。但是,检查指针的有效性不是 public 接口的一部分
- 然而,像
valgrind
这样的调试工具通常会用检查器包装函数以验证例程的使用
只是为了解释 mysql 源代码片段的作用,这可能对您有所帮助。
首先,它不是静态分配数组的测试。它尝试测试数组和 header 是否连续分配(一个紧接着另一个)。
if (array->buffer == (uchar *)(array + 1))
array->elements= 0;
这实际上是获取一个指向结构 DYNAMIC_ARRAY
的指针,并检查数组的地址是否指向结构本身之后的地址。
如果结构和数组 space 是在一个单独的 malloc() - 一个连续的块中分配的,则测试为真。例如:
DYNAMIC_ARRAY *dap = NULL ;
dap = malloc( sizeof(DYNAMIC_ARRAY) + arraylength ) ;
dap->buffer = (uchar *)(dap+1) ;
IMO,这是一段不安全的代码,因为它做出了危险的假设。
它假定两个单独的分配,一个 header 结构和一个数组 space,不能在内存中相互跟随。这不在应用程序的控制范围内,除非他们已经明确编码他们自己的内存管理器不这样做。
如果 mysql 来源中的其他地方使用了这个技巧,我会非常震惊,因为它只是在自找麻烦。
我想知道如何检查数组是静态分配的还是动态分配的。我在网上查了一下 mysql source code 中的实现,不知道为什么? (第 0303 行检查数组是否为静态)
/*
0301 Just mark as empty if we are using a static buffer
0302 */
0303 if (array->buffer == (uchar *)(array + 1))
0304 array->elements= 0;
这是DYNAMIC_ARRAY在mysql中的定义:
341
342 typedef struct st_dynamic_array
343 {
344 uchar *buffer;
345 uint elements,max_element;
346 uint alloc_increment;
347 uint size_of_element;
348 } DYNAMIC_ARRAY;
你不能。
您在这里缺少一些上下文。 在这种特殊情况下,已知 array->buffer
指向 (uchar*)(array + 1)
并且是静态分配的, 或 它指向某处else 并且是动态分配的。
但是 (uchar*)(array + 1)
并没有自动意味着某些东西是静态分配的。
这就像问这个函数如何找到数组的长度(即它不会,除非数组以0结尾):
int getArrayLength(int *a)
{
for(int i = 0; ; i++)
if(a[i] == 0)
return i + 1;
}
你不能 - 没有额外的信息。
对于C,数组就是一堆内存地址。 a[n]
其实就是(type(a))*((void*)&a+n*sizeof(a))
。它根本不关心它是如何(或是否)分配的,甚至地址是否真实。
附加信息可能是:
- 该变量属于特定类型,其中包含您可以检查所需信息的字段
- 这是你的情况:你提供的代码 "knows" 变量是
DYNAMIC_ARRAY
- 这是你的情况:你提供的代码 "knows" 变量是
- 从分配系统获取提示
- 例如
free
和realloc
只能用之前由malloc
给出的指针调用。但是,检查指针的有效性不是 public 接口的一部分- 然而,像
valgrind
这样的调试工具通常会用检查器包装函数以验证例程的使用
- 然而,像
- 例如
只是为了解释 mysql 源代码片段的作用,这可能对您有所帮助。
首先,它不是静态分配数组的测试。它尝试测试数组和 header 是否连续分配(一个紧接着另一个)。
if (array->buffer == (uchar *)(array + 1))
array->elements= 0;
这实际上是获取一个指向结构 DYNAMIC_ARRAY
的指针,并检查数组的地址是否指向结构本身之后的地址。
如果结构和数组 space 是在一个单独的 malloc() - 一个连续的块中分配的,则测试为真。例如:
DYNAMIC_ARRAY *dap = NULL ;
dap = malloc( sizeof(DYNAMIC_ARRAY) + arraylength ) ;
dap->buffer = (uchar *)(dap+1) ;
IMO,这是一段不安全的代码,因为它做出了危险的假设。
它假定两个单独的分配,一个 header 结构和一个数组 space,不能在内存中相互跟随。这不在应用程序的控制范围内,除非他们已经明确编码他们自己的内存管理器不这样做。
如果 mysql 来源中的其他地方使用了这个技巧,我会非常震惊,因为它只是在自找麻烦。