将指向内存缓冲区的指针转换为指向 VLA 的指针
Casting pointer to memory buffer to pointer to VLA
在 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]
类型.
是的,这是合法的,是的,可变修改类型系统非常有用。您可以使用自然数组语法来访问连续的二维数组,其维度直到运行时才为人所知。
它可以被称为语法糖,因为没有它们就不能用这些类型做任何事情,但它有助于干净的代码(在我看来)。
我会说它是有效的。 Final version of the C99 standard (cited on Wikipedia) 在第 7.5.2 段 - 数组声明符 alinea 5 中说:
如果大小是一个不是整数常量表达式的表达式:...
每次评估时,它的值都应大于零。每个实例的大小
可变长度数组类型在其生命周期内不会改变。
它甚至明确表示它可以用于 sizeof
只要尺寸不变 :
表达式是 sizeof 运算符的操作数的一部分并更改
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
};
...
在 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]
类型.
是的,这是合法的,是的,可变修改类型系统非常有用。您可以使用自然数组语法来访问连续的二维数组,其维度直到运行时才为人所知。
它可以被称为语法糖,因为没有它们就不能用这些类型做任何事情,但它有助于干净的代码(在我看来)。
我会说它是有效的。 Final version of the C99 standard (cited on Wikipedia) 在第 7.5.2 段 - 数组声明符 alinea 5 中说: 如果大小是一个不是整数常量表达式的表达式:... 每次评估时,它的值都应大于零。每个实例的大小 可变长度数组类型在其生命周期内不会改变。
它甚至明确表示它可以用于 sizeof
只要尺寸不变 :
表达式是 sizeof 运算符的操作数的一部分并更改
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
};
...