ANSI-C语法 – 像[*]等的数组声明

来自 -link-的ANSI C语法给出了以下关于数组声明的规则:
(1) | direct_declarator '[' type_qualifier_list assignment_expression ']'
 (2) | direct_declarator '[' type_qualifier_list ']'
 (3) | direct_declarator '[' assignment_expression ']'
 (4) | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']'
 (5) | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']'
 (6) | direct_declarator '[' type_qualifier_list '*' ']'
 (7) | direct_declarator '[' '*' ']'
 (8) | direct_declarator '[' ']'

现在我有一些关于这些的问题:

>只能在C99中使用(1) – (6)(3)除外
>(4)和(5)是什么?关键字“静态”让我感到困惑
>哪里使用(6)?
>以下两个功能原型有什么区别?

void foo(int [*]);和

void foo(int []);

谢谢.

解决方法

您不能在C89 / 90中使用数组声明的类型限定符或静态大小部分.这些功能特定于C99.

数组声明中的static告诉编译器,您承诺指定数量的元素将始终作为实际参数传递的数组中存在.这可能有助于编译器生成更有效的代码.如果您在实际代码中违反了您的承诺(即传递较小的数组),则行为是未定义的.例如,

void foo(int a[static 3]) {
  ...
}

int main() {
  int a[4],b[2];
  foo(a); /* OK */
  foo(b); /* Undefined behavior */
}

数组声明的*大小部分仅在函数原型声明中使用.它表示数组具有可变长度(VLA).例如,在功能定义中,您可以使用具体运行时大小的VLA

void foo(int n,int a[n]) /* `a` is VLA because `n` is not a constant */
{
  ...
}

当您声明原型时,您可以做同样的事情

void foo(int n,int a[n]); /* `a` is VLA because `n` is not a constant */

但是如果不指定参数名称(在原型中可以),那么当然不能使用n作为数组大小.然而,如果您仍然要告诉编译器该阵列将是一个VLA,您可以使用*来实现该目的

void foo(int,int a[*]); /* `a` is VLA because size is `*` */

注意,具有1D阵列的示例不是一个好的例子.即使你省略了*并声明了上述的功能

void foo(int,int a[]);

那么代码仍然可以正常工作,因为在函数参数声明中,数组类型反而用指针类型隐含地替换.但一旦开始使用多维数组,正确使用*变得很重要.例如,如果函数被定义为

void bar(int n,int m[n][n]) { /* 2D VLA */
  ...
}

原型可能如下所示

void bar(int n,int m[n][n]); /* 2D VLA */

或作为

void bar(int,int m[*][*]); /* 2d VLA */

在后一种情况下,第一个*可以省略(因为数组到指针的替换),而不是第二个*.

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录<future>future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...