将指向内存缓冲区的指针转换为指向VLA的指针

时间:2015-02-15 09:51:09

标签: c arrays pointers c99

在C中,我相信以下程序是有效的:将指向已分配内存缓冲区的指针转换为如下数组:

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

#define ARRSIZE 4

int *getPointer(int num){
    return malloc(sizeof(int) * num);
}

int main(){
    int *pointer = getPointer(ARRSIZE);
    int (*arrPointer)[ARRSIZE] = (int(*)[ARRSIZE])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;
}

(输出 4 )。

但是,在C99中,使用VLA进行此操作是否安全?

    int arrSize = 4;
    int *pointer = getPointer(arrSize);
    int (*arrPointer)[arrSize] = (int(*)[arrSize])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;

(也输出 4 )。

根据C99标准,这是否合法?

如果它是合法的,那就太奇怪了,因为这意味着VLA有效地启用了动态类型创建,例如类型type(*)[variable]

2 个答案:

答案 0 :(得分:7)

是的,这是合法的,是的,可变修改类型系统非常有用。您可以使用自然数组语法来访问连续的二维数组,这两个数组的维度在运行时都是未知的。

它可以被称为语法糖,因为你不能用这些类型做什么,你不可能没有它们,但它会产生干净的代码(在我看来)。

答案 1 :(得分:2)

我会说这是有效的。 Final version of the C99 standard(引自Wikipedia)在第7.5.2段中说 - 数组声明符alinea 5: 如果size是一个不是整数常量表达式的表达式:... 每次评估时,它的值应大于零。每个实例的大小 可变长度数组类型在其生命周期内不会改变

它甚至明确表示可以在sizeof 中使用它,只要尺寸永不改变其中大小 expression是sizeof运算符的操作数的一部分并且更改了value的值 size表达式不会影响运算符的结果,是否未指定 评估大小表达式

但是标准还说这只允许在块作用域声明符或函数原型中使用:具有可变修改类型的普通标识符(如6.2.3中所定义)应具有 阻止范围,没有链接或功能原型范围。如果声明了标识符 要成为具有静态存储持续时间的对象,它不应具有可变长度数组类型。

后面的一个例子说明它不能用于成员字段,即使在块范围内也是如此:

...
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m]; // valid: block scope typedef VLA
    struct tag {
        int (*y)[n]; // invalid: y not ordinary identifier
        int z[n]; // invalid: z not ordinary identifier
    };
...