文章内容源自《GPU编程与CG语言之阳春白雪下里巴人》,因笔者读书易中途放弃,遂每读一章节,将其移至简书平台,以此作为对自己读书的勉励。笔者用粗体、斜体 标注了关键词句,望感兴趣的读者们一起学习共勉。猛戳这里查看更多!
通过第 5 章到第 7 章的阅读,我们已经知道了怎么声明变量(第 5 章),怎么写表达式和语句(第 6 章),怎么将输入 \ 输出参数绑定到语义词(第 7 章),本章将首先描述 Cg 语言中函数的写法,以及函数是否可以重载;然后阐述顶点 \ 片段着色程序中入口函数的概念(类似 C\C++中的 main()函数);最后,以 Cg 标准函数库来结束本章。
函数可以被看作一个由用户定义的操作。Cg 语言中的函数声明形式与 C\C++中相同,由返回类型(return type)、函数名、形参列表(parameter list,位于括号中,并用逗号分隔的参数表)和函数体组成。函数体包含在花括号中。 如果没有返回值,则函数的返回类型是 void。下面是函数定义的例子:
void myFunc(inout float val )
{
......
val += 10.0;
}
float myFunc(float vals[])
{
float sum = 0.0;
......
return sum;
}
注意:如果函数没有返回值,函数的返回类型一定要是 void,否则编译会出现大量的错误,错误信息的大概形式是:
error C0000: syntax error, unexpected’(’at token “(”
error C0501: type name expected at token “(”
error C1110: function “main_v” has no return statement
参数传递机制是函数概念中的重中之重,请参阅 7.4 节“输入\输出修辞符”中的论述。此外,有一个比较特殊的函数形参类型,不论在 C\C++中还是在 Cg 语言中,都是一个令人头疼的话题,它就是数组形参。
在 C\C++中,当一个数组作为函数的形参时,实际上传入的只是指向首元素的指针,并且数组边界被忽略(参阅 stephen C.Dewhurst 所著的《C++必知必会》)。 而在 Cg 语言中不存在指针机制(图形硬件不支持),数组作为函数形参,传递的是数组的完整拷贝。关于 Cg 中形参数组的原始资料可以在文献[3]Array 章节中查到:
“The most important difference from C is that arrays are first-class types. That means array assignments actually copy the entire array, and arrays that are passed as parameters are passed by value, rather than by reference”.
这段英文中描述道,Cg 语言中数组是“first-class types”,中文翻译为“第一类数据类型”,所谓“第一类(first-class)”的含义是,强调该类型数据是“不可分解的、高级别的、不被重述的”,即“第一类数据类型”和“基础数据类型”的概念是近同的。如有兴趣深入了解“first-class”概念,可参阅 Matthieu Sozeau and Nicolas Oury 所著的“First-Class Type Classes”一文。
数组类型变量作为函数形参,可以是一维的也可以是多维的,并且不必声明数组长度,即 Unsized Array。例如:
float myFunc( float vals[])
{
float sum = 0.0;
for(int i = 0; i< vals.length; i++)
{
sum += vals[i];
}
return sum;
}
myFunc 是一个函数,输入一个数组变量,计算数组中所有数据之和,然后返回 float 类型数据。请注意:数组形参不必指定长度。如果指定了函数中形参数组的长度,那么在调用该函数时实参数组的长度和形参数组的长度必须保持一致,如果没有保持一致,编译时会出现错误提示信息:error C1102: incompatible type for parameter…
。
float myFunc( float vals[3])
{
float sum = 0.0;
for(int i = 0; i< vals.length; i++)
{
sum += vals[i];
}
return sum;
}
void main(…)
{
float a[2] = {0.0, 1.0};
float b[3] = {0.0, 1.0, 2.0};
myFunc(a); //错误调用,会导致编译错误
myFunc(b); //正确调用
}
对于函数的形参数组最好不要指定长度,这样就可以片配任意长度的参数数组。
如果函数的形参数组是多维数组,其声明方式和上面是一样的,可以不指定长度;如果指定形参数组长度,则实参数组长度必须保持一致。