Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在C中使用类似宏的函数访问矩阵元素安全吗?_Arrays_C_Matrix - Fatal编程技术网

Arrays 在C中使用类似宏的函数访问矩阵元素安全吗?

Arrays 在C中使用类似宏的函数访问矩阵元素安全吗?,arrays,c,matrix,Arrays,C,Matrix,我有一个矩阵结构,定义如下: struct matrix_double_complex { double complex *data; int number_of_rows; int number_of_columns; }; typedef struct matrix_double_complex MatrixDoubleComplex; MATRIX_DOUBLE_COMPLEX_ELEMENT(result,i,j) = MATRIX_DOUBLE_COMPLE

我有一个矩阵结构,定义如下:

struct matrix_double_complex
{
    double complex *data;
    int number_of_rows;
    int number_of_columns;
};

typedef struct matrix_double_complex MatrixDoubleComplex;
MATRIX_DOUBLE_COMPLEX_ELEMENT(result,i,j) = MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix_1,i,j) + MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix_2,i,j);

MATRIX_DOUBLE_COMPLEX_ELEMENT(result,i,j) = conj( MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix,j,i) );
我使用一维动态数组来存储矩阵元素,因为我想将它们存储在单个内存块中

结构在此函数中初始化:

MatrixDoubleComplex * matrix_double_complex_initialize(int number_of_rows, int number_of_columns)
{
    MatrixDoubleComplex *matrix;

    matrix = (MatrixDoubleComplex *)malloc( sizeof(MatrixDoubleComplex) );

    
    if(matrix == NULL)
    {
        fprintf(stderr, "matrix_double_complex_initialize: Error!\n");
        exit(EXIT_FAILURE);
    }

    
    matrix->data = (double complex *)malloc( (number_of_rows)*(number_of_columns)*sizeof(double complex) );

    
    if( (matrix->data) == NULL )
    {
        fprintf(stderr, "matrix_double_complex_initialize: Error!\n");
        exit(EXIT_FAILURE);
    }


    matrix->number_of_rows = number_of_rows;
    matrix->number_of_columns = number_of_columns;

    return matrix;
}
但我不能使用方便的语法,如
matrix->data[I][j]
来访问矩阵元素

我知道我需要计算索引:
矩阵->数据[(i-1)*(矩阵->列数)+(j-1)]

但这是丑陋的语法

我有“设置”和“获取”函数来访问矩阵元素:

void matrix_double_complex_set_element(MatrixDoubleComplex *matrix, int i, int j, double complex z)
{
    matrix->data[ (i - 1)*(matrix->number_of_columns) + (j - 1) ] = z;
}

double complex matrix_double_complex_get_element(MatrixDoubleComplex *matrix, int i, int j)
{
    return ( matrix->data[ (i - 1)*(matrix->number_of_columns) + (j - 1) ] );
}
但我不能把这些函数用作左边。我还需要使用一些额外的变量和函数调用

void matrix_double_complex_add(MatrixDoubleComplex *result, MatrixDoubleComplex *matrix_1, MatrixDoubleComplex *matrix_2)
{
    if( matrices_double_complex_have_the_same_dimension(result, matrix_1) == false )
    {
        fprintf(stderr, "matrix_double_complex_add: Error!\n");
        exit(EXIT_FAILURE);
    }

    if( matrices_double_complex_have_the_same_dimension(matrix_1, matrix_2) == false )
    {
        fprintf(stderr, "matrix_double_complex_add: Error!\n");
        exit(EXIT_FAILURE);
    }
    
    double complex result_ij;
    double complex matrix_1_ij;
    double complex matrix_2_ij;
        
    for(int i = 1; i <= (result->number_of_rows); i++)
    {
        for(int j = 1; j <= (result->number_of_columns); j++)
        {
            matrix_1_ij = matrix_double_complex_get_element(matrix_1, i, j);
            matrix_2_ij = matrix_double_complex_get_element(matrix_2, i, j);

            result_ij = matrix_1_ij + matrix_2_ij;

            matrix_double_complex_set_element(result, i, j, result_ij);
        }
    }
}
使用此宏,我可以方便地编写如下内容:

struct matrix_double_complex
{
    double complex *data;
    int number_of_rows;
    int number_of_columns;
};

typedef struct matrix_double_complex MatrixDoubleComplex;
MATRIX_DOUBLE_COMPLEX_ELEMENT(result,i,j) = MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix_1,i,j) + MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix_2,i,j);

MATRIX_DOUBLE_COMPLEX_ELEMENT(result,i,j) = conj( MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix,j,i) );

所以,我的问题是:使用这个宏安全吗?在某些情况下,它会导致未定义的行为吗?

因为您正确地将
i
j
括起来,并且只使用它们一次,所以这些参数是安全的。如果以复杂的方式使用
矩阵
参数,理论上是不安全的,例如,将指针算术与
++
/
--
一起用于矩阵数组中的指针。在这种情况下,评估
矩阵
的副作用将发生两次,在以下情况下产生未定义的行为:

 MATRIX_DOUBLE_COMPLEX_ELEMENT(*matrixptr++, 0, 1)
计算(因为在展开表达式中出现两次
matrixptr++
)。如果调用一个非幂等函数或具有副作用的函数来生成
矩阵
参数,则可能会出现类似的问题。只要您坚持简单的用法(矩阵的
参数始终是一个简单的变量名),这就行了

如果您想消除这种误用的风险,可以使用一个函数来检索指向矩阵元素的指针;取消对结果的引用,它可以用于读取和写入该元素。如果需要,宏可以包装该函数,其中宏为您执行解引用,同时保持函数提供的单一求值行为:

double complex* matrix_double_complex_get_element_ptr(MatrixDoubleComplex *matrix, int i, int j)
{
    // Returns address of element, not element value
    return &matrix->data[ (i - 1)*(matrix->number_of_columns) + (j - 1) ];
}

#define MATRIX_DOUBLE_COMPLEX_ELEMENT(matrix,i,j) \
  (*matrix_double_complex_get_element_ptr((matrix), (i), (j)))

您可以像使用原始的、可能不安全的宏一样使用它,而不会对复杂的(如形容词,而不是数据类型)
matrix
参数进行双重计算。您可以将函数本身声明为显式
inline
函数,以降低开销;编译器应该能够避免采用地址/取消引用两步,使代码的性能相当于手工编写更复杂的表达式。

IMO宏应该避免,只有在绝对必要时才使用。 宏极易出错,尤其是在以下情况下:

  • 不使用括号
  • 您可以使用多个特定参数(
    #define SQR(x)(x)*(x)
    y=SQR(x++);
  • 宏内部的函数调用有副作用
  • 如果您担心函数调用开销,那么编译器很可能会自动内联它们。如果你知道编译器,你也可以强制内联

    gcc
    示例:

    inline __attribute__((always_inline)) double complex* matrix_double_complex_get_element_ptr(MatrixDoubleComplex *matrix, int i, int j)
    {
        // Returns address of element, not element value
        return &matrix->data[ (i - 1)*(matrix->number_of_columns) + (j - 1) ];
    } 
    

    宏没有问题。在预处理器上下文中,没有太多事情可以导致UB,这里也没有。例如,如果矩阵
    NULL
    ,它肯定会导致UB,但这与它是一个宏这一事实并不相关。它是安全的,只需放置大量()是否要使用索引
    1。。行数
    而不是通常的
    0。。(行数-1)
    ?这可能会让C程序员感到困惑。博多,我不确定。但是数学家通常把矩阵元素写成a{11},a{12},。。。