跳转到主要内容

一个预处理程序,它为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 可以省略。 endstride 也可以省略,但如果要指定它们后面的条目,则必须保留它们的尾随冒号。例如,轴指定 :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日)

  • 语法从c[i;j]更改为c[i,j]

  • 对真实头文件的更多解析器支持。

2011.3

(2012年12月10日)

  • 语法从c(i,j)更改为c[i;j]

  • 对许多GNU扩展的解析器支持,现在在OS X(10.7)和Linux上也能使用tgmath.h

2011.2

(2012年12月10日)

  • 语法从c[i,j]更改为c(i,j)

  • 对OS X的修复和两个错误。

  • 生成#line指令。

2011.1

(2012年12月9日)

初始发布。

未来功能

  • 缓存词法分析器/解析器表(更快启动)

  • 边界检查。

作者

Andreas Kloeckner <inform@tiker.net>,基于与Zydrunas Gimbutas的讨论。

项目详细信息


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源分发

cnd-2012.1.tar.gz (100.6 kB 查看哈希)

上传时间: