[英]Macros in C for getting/setting entries of an array
下面的小代碼輸入一個矩陣,該矩陣具有行優先順序和兩列。 據我了解,我所包含的宏將使我能夠以更自然的方式(從1索引開始)訪問數組的條目。
#define Alocal(i,j) Alocal[ (j-1) + 2*(i-1) ]
void test_function(double* Alocal)
{
double a;
double b;
/* get first and second entries of the array */
a = Alocal(1,1);
b = Alocal(1,2);
}
現在我有兩個問題:1)說我將整數Ncols
傳遞給函數。 可以在宏中使用它以獲得更籠統的定義嗎? 喜歡
#define Alocal(i,j) Alocal[ (j-1) + Ncols*(i-1) ]
2)有沒有一種方法可以定義將數組的特定條目設置為宏中的某個數字? 喜歡
double d;
d = 3.4579;
Alocal(2,2) = d;
void
方式),可以至少將MY_ARRAY_SET
宏放入do{ ... }while(0)
塊中。 我沒有特別注意您的索引計算,請參閱Ben的答案
#include <stdlib.h>
#define MY_ARRAY_GET(array,i,j) ( (array)[ ((j)-1) + 2*((i)-1) ] )
#define MY_ARRAY_SET(array,i,j,x) ( (array)[ ((j)-1) + 2*((i)-1) ] = (x) )
void test_function(double* Alocal)
{
double a;
double b;
/* get first and second entries of the array */
a = MY_ARRAY_GET(Alocal, 1, 1);
b = MY_ARRAY_GET(Alocal, 1, 2);
MY_ARRAY_SET(Alocal, 1, 2, 42.0);
}
int main(int argc, char** argv)
{
double array[16] =
{ 1.0, 2.0 }; //Initialize to 1.0,2.0,0.0 ...
test_function(array);
return EXIT_SUCCESS;
}
試圖將想法和其他答案和評論(VLA和斷言)放在一起。 免責聲明:這是一種概念證明,而不是我如何編寫高效的代碼。
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
//********************************************************************************
//Utility macros
/**
* @brief Internal macros to retrieve the dynamic size of a VLA dimension 1
* @param vla A pointer to the VLA is need in order to properly deduce its dimensions
* @warning for internal use only
*/
#define INTERNAL_VLA_SIZE_D1(vla) (sizeof((*vla))/sizeof((*vla)[0]))
/**
* @brief Internal macros to retrieve the dynamic size of a VLA dimension 2
* @param vla A pointer to the VLA is need in order to properly deduce its dimensions
* @warning for internal use only
*/
#define INTERNAL_VLA_SIZE_D2(vla) (sizeof((*vla)[0])/sizeof((*vla)[0][0]))
//********************************************************************************
//Debug check helper
int is_valid_index_2D(const size_t nrows, const size_t ncols, const size_t row, const size_t col)
{
return (nrows) && (ncols) && ((size_t) (row) < (size_t) (nrows)) && ((size_t) (col) < (size_t) (ncols));
}
//********************************************************************************
//1 based index loop macros
#define FOR_RANGE(type,var,start,end) \
for(type var = (start);var <= (end);++var)
#define FOR(type,var,count) \
FOR_RANGE(type,var,1,count)
#define MAT_FOREACH_INDEX(rowvar,colvar,mat) \
FOR(size_t,rowvar,INTERNAL_VLA_SIZE_D1(&(mat))) \
FOR(size_t,colvar,INTERNAL_VLA_SIZE_D2(&(mat)))
//********************************************************************************
//Matrix functions
//Note: These functions rely upon compiler warnings or errors regarding incompatible pointer types
// (i.E. for a wrong number of array dimensions)
void mat_set(const size_t nrows, const size_t ncols, double (* const matrix)[nrows][ncols], const size_t row, const size_t col, const double value)
{
assert(is_valid_index_2D(nrows,ncols,row,col));
(*matrix)[row][col] = value;
}
double mat_get(const size_t nrows, const size_t ncols, double (* const matrix)[nrows][ncols], const size_t row, const size_t col)
{
assert(is_valid_index_2D(nrows,ncols,row,col));
return (*matrix)[row][col];
}
void mat_identity(const size_t nrows, const size_t ncols, double (* const matrix)[nrows][ncols], double value)
{
for (int row = 0; row < nrows; ++row)
for (int col = 0; col < ncols; ++col)
(*matrix)[row][col] = row == col ? value : 0.0;
}
void mat_fprintf(FILE* stream, const char* const field_delim, const char* const field_format, const size_t nrows, const size_t ncols, double (* const matrix)[nrows][ncols])
{
for (int row = 0; row < nrows; ++row)
{
for (int col = 0; col < ncols; ++col)
{
if (col)
fputs(field_delim, stream);
fprintf(stream, "%.2f", (*matrix)[row][col]);
}
fprintf(stream, "\n"); //write a line break, the portable way
}
}
//Matrix utility macros, using 1 based indices
#define MAT_SET(mat,row,col,value) \
mat_set(INTERNAL_VLA_SIZE_D1(&(mat)),INTERNAL_VLA_SIZE_D2(&(mat)),(&(mat)),(row)-1,(col)-1,value)
#define MAT_GET(mat,row,col) \
mat_get(INTERNAL_VLA_SIZE_D1(&(mat)),INTERNAL_VLA_SIZE_D2(&(mat)),(&(mat)),(row)-1,(col)-1)
#define MAT_SET_IDENTIY(mat,value) \
mat_identity(INTERNAL_VLA_SIZE_D1(&(mat)),INTERNAL_VLA_SIZE_D2(&(mat)),(&(mat)),value)
#define MAT_FPRINTF(stream,field_delim,field_format,mat) \
mat_fprintf((stream),(field_delim),(field_format),INTERNAL_VLA_SIZE_D1(&(mat)),INTERNAL_VLA_SIZE_D2(&(mat)),(&(mat)))
#define MAT_PRINTF(field_delim,field_format,mat) \
MAT_FPRINTF(stdout,(field_delim),(field_format),(mat))
int main(int argc, char** argv)
{
#ifdef NDEBUG
fprintf(stderr, "assertions disabled\n");
#else
fprintf(stdout, "assertions enabled\n");
#endif
//Note: since below VLA is created on stack, we must be cautious about its size
for (size_t nrows = 1; nrows <= 5; ++nrows)
{
for (size_t ncols = 1; ncols <= 5; ++ncols)
{
//Allocate the matrix on stack
double matrix[nrows][ncols];
//Initialize matrix to identity
MAT_SET_IDENTIY(matrix, 1.0);
puts("****************************************");
//Print the matrix using a wrapped function
MAT_PRINTF(", ", "%.2f", matrix);
puts("****************************************");
//Print the matrix using nested loops with 1 based indices
FOR(size_t,row,nrows)
FOR(size_t,col,ncols)
{
printf("%.2f", MAT_GET(matrix, row, col));
if (col < ncols)
printf(", ");
else
printf("\n");
}
puts("****************************************");
//Print the matrix using a 2D foreach with 1 based indices
MAT_FOREACH_INDEX(row, col, matrix)
{
printf("%.2f", MAT_GET(matrix, row, col));
if (col < ncols)
printf(", ");
else
printf("\n");
}
}
}
return EXIT_SUCCESS;
}
您所說的所有內容都可以正常運行。 只需確保已將Ncols
定義為宏或變量即可。
此方法有效,因為您的宏簡單地創建到原來的數組的元素的引用,並且所述代碼運行時,使用除了像test[1+2]
將同樣的事情test[3]
結果,獲取和設置元素的工作方式都與硬編碼數組查找而不是使用宏的方式相同。 因此,再舉一個例子: Alocal(2,2) = d
將有效地意味着(一旦您完成了減法和乘法運算,並假設NCol
為2): Alocal[3] = d
,這是完全正常的C。
另外,作為一個旁注,如果知道預先需要多少列,也可以使用多維數組,假設是二維數組,則該數組會使您的宏看起來更像這樣:
#define Alocal(i,j) Alocal[ (j-1) ][ (i-1) ]
內置語言功能可解決此問題,因此您不應為此使用宏。
自1999年以來,C具有可變長度數組 VLA,可以完美地完成這項工作。 將原型更改為
void test_function(size_t ncol, double (*A)[ncol]);
然后,您的編譯器將完全知道如何獨自完成諸如A[i][j]
類的索引計算。
在上面的原型,重要的是要有ncol
前A
,使得它在的參數說明點是已知的A
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.