TLDR:这是在Linux邮件列表的讨论中创建的特殊语法,用于在声明变量之前表示VLA的大小,.n
中的.
表示n
引用当前函数声明中的参数,但n
可能出现在当前声明的参数之后.他们还将通常的int a[restrict n]
参数声明扩展为void
类型.我不知道在官方文档中哪里可以找到这样的语法,但邮件列表中有所有的细节.
LINUX库函数手册中对memcpy
语法的更改是在commit c64cd13e版中引入的.提交消息被逐字复制到此处以供参考.
各个页面:概要:在‘void*’函数参数中使用VLA语法
也可以使用VLA语法来表示空*,尽管它会更奇怪一些.
诚然,从C语言的Angular 来看,这已经够奇怪的了,因为虽然void f(int n, int[restrict n])
是有效的VLA语法,但void f(int n, void[restrict n])
不是,因为我们不允许有void
的array.
对于n
之前的.
,如果我们更深入地挖掘,我们可以从linux-man
mailing list中找到this thread.
让我们举个例子:
int getnameinfo(const struct sockaddr *restrict addr,
socklen_t addrlen,
char *restrict host, socklen_t hostlen,
char *restrict serv, socklen_t servlen,
int flags);
以及一些转变:
int getnameinfo(const struct sockaddr *restrict addr,
socklen_t addrlen,
char host[restrict hostlen], socklen_t hostlen,
char serv[restrict servlen], socklen_t servlen,
int flags);
int getnameinfo(socklen_t hostlen;
socklen_t servlen;
const struct sockaddr *restrict addr,
socklen_t addrlen,
char host[restrict hostlen], socklen_t hostlen,
char serv[restrict servlen], socklen_t servlen,
int flags);
(我不确定我是否使用了正确的GNU语法,因为我从未使用过
扩展我自己.)
上面的第一个转换是毫不含糊的,尽可能简洁,
唯一的问题是,它可能会使实现稍微复杂化
太多.我不认为超前-使用参数的大小会太过
对于人类读者来说,这是一个很大的解析问题.
我个人认为第二种形式并不可怕.能够阅读
代码从左到右、自上而下在更复杂的示例中很有帮助.
第二个是不必要的冗长和冗长,而分号不是
与逗号非常不同,对于人类读者来说,这可能非常
令人困惑.
int foo(int a; int b[a], int a);
int foo(int a, int b[a], int o);
这两个对于编译器来说非常不同,但又非常类似于
人类的眼睛.我不喜欢这个.事实上,它允许更简单的
编译器不足以克服可读性问题.
这是真的,我可能会将其与逗号和/或语法一起使用
突出显示.
我想我更喜欢将向前使用的语法作为非标准语法
扩展--或标准但可选的语言功能--以避免
迫使小型编译器实现它,而不是让GNU
在所有编译器中标准化的扩展.
第二种形式的问题是:
- 它不是100%向后兼容的(尽管这可能是可以的),因为以下代码的语义发生了变化:
Int n;int foo(int a[n],int n);//指不同的n!
为新的编译器编写的代码可能会被旧的编译器误解
当带有‘n’的变量在作用域中时,编译器.
Int foo(int(*a)[sizeof(*b)],int(*b)[sizeof(*a)]);
我们可以考虑新的语法,例如
Int foo(char buf[.N],int n);
就我个人而言,我更喜欢Forward的概念简单性
声明和事实,这些已经存在于GCC的任何
另类 Select .我也不介意新的语法,但那是必须的
更准确地定义规则,以避免上述问题.
根据我的理解,这基本上意味着.
是一种引用在声明之前使用的VLA数组大小参数的方法,一个用例是处理相互引用.
有一个follow-up thread,上面写着,
我对语法很满意,但我不确定这是如何工作的.如果
类型是以后才确定的,您仍然需要更改解析器
(一些C编译器在解析过程中执行类型判断和折叠,因此
需要在解析过程中知道类型),并且您仍然拥有
相互依赖的问题.
我们考虑过使用以下语法
Int foo(char buf[.N],int n);
因为它是新的语法,这意味着我们可以将大小限制为
参数的名称,而不是允许任意表达式,
这就减少了前向引用的问题.它也是
与初始值设定项中的指示符一致,也可以扩展
注释灵活的数组成员或存储指向数组的指针
在 struct 中:
Struct{int n;char buf[.N];};
Struct{int n;char(*buf)[.N];};
当然,也有objection个,我想很多SO社区的人都会同意,
我唯一非常关心的是这一点:
手册页不应使用
- 非标准语法
- 不可移植的语法
- 不明确的语法(即,不同的编译器或不同的上下文中可能具有不同含义的语法)
- 对于一些广泛使用的编译器集合,如GCC或llvm,语法可能是无效的或危险的