一个预处理程序,它为C语言提供了多维数组
项目描述
CnD是一个源到源翻译器,它使得在C语言中使用n维数组变得更加愉快。它将把以下代码
void sgemm(float *a, float *b, float *c, int n) { dimension "fortran" a[n, n]; dimension "fortran" b[n, n]; dimension c[n, n]; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { float tmp = 0; for (int k = 1; k <= n; ++k) tmp += a[i,k]*b[k,j]; c[i-1,j-1] = tmp; } }
转换成这样
void sgemm(float *a, float *b, float *c, int n) { for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { float tmp = 0; for (int k = 1; k <= n; ++k) tmp += a[((k - 1) * ((n - 1) + 1)) + (i - 1)] * b[((j - 1) * ((n - 1) + 1)) + (k - 1)]; c[((i - 1) * n) + (j - 1)] = tmp; } }
您还可以查看一个更全面的示例,展示了几个额外的功能。
维度 声明的唯一效果是修改了对 array(idx) 索引运算符的解释。 维度 声明遵循常规C作用域规则。
我还想指出,CnD是一个健壮的、基于解析器的翻译器,不是一个易出故障的文本替换工具。它理解所有C99标准,以及许多GNU扩展。
维度 声明中的每个轴指定具有以下形式
start:end:stride:leading_dimension
start 可以省略。 end 和 stride 也可以省略,但如果要指定它们后面的条目,则必须保留它们的尾随冒号。例如,轴指定 :5 只简单地指定了步长为5。步长只是作为索引的乘数。对维度声明不进行任何合理性检查。您可以以任何您喜欢的方式让自己受伤。
如果布局指定为 “c” 或 “row-major” 或未指定,以下情况成立
数组以行主序排列。
如果指定了 end 索引,则假定它是排他的。
如果未指定 start 索引,则默认为0。
如果布局指定为 “col-major”,以下情况成立
数组以列主序排列。
如果指定了 end 索引,则假定它是排他的。
如果未指定 start 索引,则默认为0。
如果布局指定为 “fortran”,以下情况成立
数组以列主序排列。
如果指定了 end 索引,则假定它是包含的。
如果未指定 start 索引,则默认为1。
(大多数)维度 声明中包含的知识可以通过以下函数以编程方式重新获取
rankof(a)
nitemsof(a)
lboundof(a, axis)
uboundof(a, axis)(返回用户指定的上界)
puboundof(a, axis)(返回轴末尾的索引)
ldimof(a, axis)
strideof(a, axis)
在每种情况下,轴必须是一个常量整数(不是一个常量表达式,一个纯整数)。
安装/使用
您可以通过从软件包索引或从GitHub下载tarball来获取CnD。
$ git clone git://github.com/inducer/cnd.git $ cd cnd $ git submodule init $ git submodule update
要使用CnD,只需将distribution-dir/bin添加到您的PATH。
要开始使用,只需运行(在cnd根目录下)
$ cd examples $ ../bin/cndcc gcc -std=c99 basic.c $ ./a.out
如果您想对翻译过程有更细致的控制,cnd命令只提供源到源翻译。请注意,cnd期望预处理过的源代码。您可以传递选项-E,让cnd为您运行预处理程序。运行
$ cnd -h
以获取命令行界面的完整帮助。您可以将环境变量CND_CPP设置为要使用的预处理程序。
常见问题解答
这个语法不也有预处理程序的问题吗?
非常好的观点。考虑以下情况
#define MY_MACRO(a) /* something rather */ MY_MACRO(array[i,j])
预处理程序看到逗号,将我们的数组访问拆分成两个宏参数,然后抱怨说MY_MACRO只接受一个参数。不是很聪明,但这就是生活。(发现此问题的功劳归功于Zydrunas Gimbutas。)
最简单的修复方法是使用以下语法
MY_MACRO(array[(i,j)])
这始终是有效的。一些C标准“函数”也可能变成宏,所以原则上您在将多维度数组访问的结果传递给您未声明的函数时,必须使用这种语法。这显然不方便,所以还有另一个转折。CnD将通过在括号内插入括号(在非字符串、非字符常量、非预处理程序上下文中)来重写您的源主文件(但不包括任何包含的头文件)。这在C99中是无效操作。因此,您必须仅在不是顶层编译文件的文件和数组访问可能是宏展开部分的情况下使用括号语法。
版本历史
2011.4
(2012年12月11日)
2011.3
(2012年12月10日)
2011.2
(2012年12月10日)
2011.1
(2012年12月9日)
初始发布。
未来功能
缓存词法分析器/解析器表(更快启动)
边界检查。