在Objective-C中正向声明具有已定义数组大小的函数

在Objective-C中正向声明具有已定义数组大小的函数,c,arrays,function,C,Arrays,Function,我确信这是一个相当愚蠢的问题,但它确实让我措手不及,可能是我没有正确地思考这个问题。在使用OpenGL ES 2.0时,我遇到了以下代码行 ///////////////////////////////////////////////////////////////// // Forward declarations static void SceneMeshInitIndices( GLushort meshIndices[NUM_MESH_INDICES]); static void

我确信这是一个相当愚蠢的问题,但它确实让我措手不及,可能是我没有正确地思考这个问题。在使用OpenGL ES 2.0时,我遇到了以下代码行

/////////////////////////////////////////////////////////////////
// Forward declarations
static void SceneMeshInitIndices(
   GLushort meshIndices[NUM_MESH_INDICES]);
static void SceneMeshUpdateNormals(
   SceneMeshVertex mesh[NUM_MESH_COLUMNS][NUM_MESH_ROWS]);
static void SceneMeshUpdateMeshWithDefaultPositions(
   SceneMeshVertex mesh[NUM_MESH_COLUMNS][NUM_MESH_ROWS]);

现在,让我措手不及的是,函数将其输入声明为具有特定大小的2D数组。我从未见过这样做,我完全不确定它是否合法或在Objective-C中如何合法。我一直被告知使用指向原始数组的指针并将其传入。但这似乎很奇怪。有谁能试着向我解释一下,或者指出我推断的错误吗?

当数组传递给函数时,它们会根据一组规则衰减为指针。这些是:

一个。第一级间接寻址(即数组的第一维/索引)衰减为指针,因此不需要指定(也不使用)其大小

两个。数组的其他维度保持不变,不会衰减为指针。需要指定它们,它们是参数类型的一部分

这就是为什么以下内容本质上是等效的和合法的:

void foo(int arr[]);
void foo(int arr[MAX_ARRAY_SIZE]);
void foo(int *arr);
void foo(int arr[MAX_ROWS][MAX_COLUMNS]);
void foo(int arr[][MAX_COLUMNS]);
但以下内容并不等同,但仍然合法:

void foo(int arr[MAX_ROWS][MAX_COLUMNS]);
void foo(int **arr);
以下内容同样同等合法:

void foo(int arr[]);
void foo(int arr[MAX_ARRAY_SIZE]);
void foo(int *arr);
void foo(int arr[MAX_ROWS][MAX_COLUMNS]);
void foo(int arr[][MAX_COLUMNS]);
(这些被解释为
int(*arr)[MAX_列])
,即。E作为指向数组的指针)

以下是非法的,i。E它会生成一个编译器错误:

void foo(int arr[MAX_ROWS][]);
我总是被告知使用指向原始数组的指针并将其传入

您被告知使用指向原始数组元素的指针。您被告知这一点是因为如果您试图声明一个按值获取数组的函数,该语言会指定参数类型被“调整”以获取指向元素类型的指针(实际上会导致数组参数类型忘记其大小,并通过引用而不是值传递)。因此,基本上你已经被告知手动进行调整,以便源代码准确、明确地表示实际情况

您显示的声明也可以使用以下建议声明:

static void SceneMeshInitIndices(GLushort *meshIndices);
static void SceneMeshUpdateNormals(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);
static void SceneMeshUpdateMeshWithDefaultPositions(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);
应该清楚的是,
int[X][Y]
的类型意味着“一个由X个数组组成的Y个数组”。因此元素类型是“一个由Y个数组组成的数组”。因此调整后的类型是“int(*)[Y]”或“一个指向Y个数组的指针”


“调整”参数类型的规则是原始数组非常糟糕的几个原因之一,如果可以避免的话,就不应该使用它。不幸的是,C并没有真正的方法来完成这一点,但是C++有<代码> STD::数组,它的行为应该是数组所应该的;i、 您可以通过值传递它们,您可以通过值返回它们,它们不会自动转换为指向元素类型的指针(因此它们永远不会忘记它们的大小),等等


也许更多的例子会让它更清楚。如果你写:

void foo(int param[10]);
如果您不知道调整参数类型的规则,那么您可能会期望以下代码产生错误:

int bar[5];
foo(bar); // error? an array of 5 ints is not the expected type.
对于此代码:

int baz[10];
foo(baz);
您可能希望将数组
复制到参数中,并且对参数所做的任何修改都不会对原始数组产生影响。不幸的是,这些完全合理的期望是错误的。当您编写
voidfoo(int-param[10])编译器看到带有数组类型的参数,并将其修改为与您编写的
void foo(int*param)相同

因此,当您编写
foo(bar)
时,编译器看到函数采用
int*
(而不是您编写的
int[10]
),看到它可以将
bar
转换为
int*
,因此编译器不报告错误,而是恶意生成一个调用函数的程序。无论您编写的类型与传递的变量不兼容,也不管
foo()
的主体可以执行类似
param[9]*=2的操作并且应该确保这是定义良好的

类似地,
foo(baz)
不按值传递数组,对函数中的数组参数所做的任何操作都直接在实际数组上完成。这与通常的C语义完全不同,在C语义中,所有内容都是按值/副本传递的,“按引用传递”的唯一方法是获取一个指针值,该指针值充当对另一个对象的引用。在这种情况下,编译器会自动代表您获取一个指针,并通过引用有效地传递数组


另外,请注意,您是否编写
voidfoo(int[10])
voidfoo(int[100])
并不重要;在这两种情况下,参数类型都被调整为
int*
,因此这些声明声明声明了相同的函数,尽管它们看起来不同。

为了验证上面提到的内容,我还发现了以下解释(基本上说明我在相当长的一段时间内不需要传递2D数组)这只是重复上面的内容

将一维数组声明为函数内的形式参数时,您了解到不需要数组的实际维度;只需使用一对空括号通知C编译器该参数实际上是一个数组。这并不完全适用于多维数组。对于二维数组,可以省略数组中的行数,但声明必须包含数组中的列数。所以声明

int array_values[100][50]
   int array_values[100][]
及 int数组_值[][50]

都是名为array_值的形式参数数组的有效声明,包含 100行50列;但是声明

int array_values[100][50]
   int array_values[100][]


不是因为必须指定数组中的列数。

我对您所引用的调整仍然有点模糊(而且我也不是新手)