我遇到了一些编译的C代码,但我不明白为什么.具体来说,我有一个C库,它有很多使用这种格式的代码:
void get_xu_col(int i_start,
int n,
double x[n],
int n_x,
int n_u,
int n_col,
double xu_col[n_col][n_x + n_u]){
...
}
int main(){
...
double xu_col[n_col][n_x + n_u];
get_xu_col( ..., xu_col );
...
}
Run Code Online (Sandbox Code Playgroud)
我不明白的是编译器允许在数组中调整大小的原因.据我所知,尺寸必须固定(例如xu_col[9][7])或未定义(例如xu_col[][]).在上面的代码中,似乎大小不是编译时常量.
编译器是否只是忽略了这里的参数?或者它是否真的在维度上进行编译时检查?
如果是后者,那么分别传递尺寸似乎容易出错.
问题的第二部分是:
为什么相同的版本在C++中不起作用?当我从字面上文件扩展名从改变.c到.cpp,并尝试重新编译,我得到
candidate function not viable: no known conversion from 'double [n_col][n_x + n_u]' to 'double (*)[n_x + n_u]' for 7th argument
void get_xu_col(int i_start, int n, double x[n], int n_x, int n_u, int n_col, double xu_col[n_col][n_x + n_u]);
Run Code Online (Sandbox Code Playgroud)
我想知道我应该用哪个成语来将这个代码转换为C++,因为显然以前的习惯用法是用C语言编写的,而不是C++.
Ste*_*ocy 59
在C中,只要大小位于参数列表中的数组之前,就可以使用函数参数来定义可变长度数组参数的大小.C++不支持此功能.
MSa*_*ers 36
它在C中工作的原因,而不是在C++中工作的原因仅仅是因为它是C代码而不是C++.这两种语言共享历史,而不是语法.
C++的方法传递可变大小的数组是std::vector,可能是由参考如果打算修改向量的函数,或者通过const 参考如果不这样做.
小智 11
我不明白的是编译器允许在数组中调整大小的原因.据我所知,大小必须固定(例如xu_col [9] [7])或未定义(例如xu_col [] []).在上面的代码中,似乎大小不是编译时常量.
你是对的,大小不是编译时常量.如果你有一个二维数组,x [line] [col],编译器需要一行中的元素数来计算一个元素的地址.查看get_char_2()和get_char_3()示例代码.
如果使用可变长度数组(VLA)作为函数参数,则必须提供这些数字(请参阅get_char_1示例).你可以写:
my_func( x[][width] )
Run Code Online (Sandbox Code Playgroud)
或者你可以写
my_func( x[999][width] )
Run Code Online (Sandbox Code Playgroud)
编译器是否只是忽略了这里的参数?或者它是否真的对维度进行了>编译时检查?
编译器将忽略第一个数字(999).第二是需要的.如果没有行大小,编译器就无法计算这些2D数组中的地址.编译器不对C中的VLA执行运行时或编译时检查.
/* file: vla.c
*
* variable length array example
*
* compile with:
*
* gcc -g -Wall -o vla vla.c
*
*/
#include <stdio.h>
#include <wchar.h>
/* 4 Lines - each line has 8 wide-characters */
wchar_t tab[][8] = {
{ L"12345678" },
{ L"abcdefgh" },
{ L"ijklmnop" },
{ L"qrstuvwx" }
};
/* memory layout:
0x00: 0x0031 0x0032 0x0033 0x0034 0x0035 0x0036 0x0037 0x0038
0x20: 0x0061 0x0062 0x0063 0x0064 0x0065 0x0066 0x0067 0x0068
...
*/
/* get character from table w/o variable length array and w/o type */
char get_char_3(int line, int col, int width, int typesize, void *ptr )
{
char ch = * (char *) (ptr + width * typesize * line + col * typesize );
printf("line:%d col:%d char:%c\n", line, col, ch );
return ch;
}
/* get character from table w/o variable length array */
char get_char_2(int line, int col, int width, wchar_t *ptr)
{
char ch = (char) (ptr + width * line)[col];
printf("line:%d col:%d char:%c\n", line, col, ch );
return ch;
}
/* get character from table : compiler does not know line length for
address calculation until you supply it (width).
*/
char get_char_1(int line, int col, int width, wchar_t aptr[][width] )
{
/* run-time calculation:
(width * sizeof(char) * line) + col
??? KNOWN KOWN KNOWN
*/
char ch = (char) aptr[line][col];
printf("line:%d col:%d char:%c\n", line, col, ch );
return ch;
}
int main(void)
{
char ch;
ch = tab[1][7]; /* compiler knows line length */
printf("at 1,7 we have: %c\n", ch );
/* sizeof tab[0][0] == sizeof(wchar_t) */
ch = get_char_1(1,7, sizeof(tab[0])/sizeof(tab[0][0]), tab);
printf("1 returned char: %c\n", ch );
ch = get_char_2(1,7, sizeof(tab[0])/sizeof(tab[0][0]), (wchar_t*)tab);
printf("2 returned char: %c\n", ch );
ch = get_char_3(1,7, sizeof(tab[0])/sizeof(tab[0][0]),
sizeof( wchar_t), tab);
printf("3 returned char: %c\n", ch );
printf("table size: %lu, line size: %lu, element size: %lu\n",
sizeof(tab),
sizeof(tab[0]),
sizeof(tab[0][0])
);
printf("number of elements per lines: %lu\n",
sizeof(tab[0])/sizeof(tab[0][0]));
printf("number of lines: %lu\n",
sizeof(tab)/sizeof(tab[0]));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它所做的一切(在C中)允许您在被调用的函数中编写索引代码而无需自己进行地址计算,例如:
double d= xu_col[i*row_size + j]; //get element [i,j]
Run Code Online (Sandbox Code Playgroud)
与
double d= xu_col[i][j];
Run Code Online (Sandbox Code Playgroud)
当参数声明为具有一维数组类型时,C忽略给定的大小,而是将参数视为指向元素类型的指针.对于嵌套(多维)数组,此类处理仅应用于外部数组.在C89中,内部尺寸必须具有固定尺寸,但在C99中尺寸可以是表达式.如果直到数组之后才列出计算数组大小所需的参数,则必须使用新旧语法的奇怪混合来声明函数,例如
int findNonzero(short dat[*][*], int rows, int cols);
int findNonzero(dat, rows, cols)
int rows,cols;
short dat[static rows][cols];
{
for (int i=0; i<rows; i++)
for (int j=0; j<cols; j++)
if (dat[i][j] != 0) return i;
return -1;
}
Run Code Online (Sandbox Code Playgroud)
请注意,数组大小*在函数原型中指定,并且函数定义不在参数列表中指定类型,而是描述参数列表和左大括号之间的所有参数类型.另请注意,虽然编译器可能会忽略数组声明中的行数,但智能编译器可能能够使用它来促进优化.实际上,奇怪的"静态"语法邀请编译器按照它认为合适的方式读取数组的任何部分,直到给定的大小,无论代码是否读取了这些值.这在某些平台上可能会有所帮助,在这些平台上,代码可能会同时处理多个数组项目而受益.