C 宏是否可以具有任何状态?在本例中,为整数值。
我希望能够从静态分配的缓冲区中分配一些内存,因为我处于嵌入式环境中。假设我有一个像这样的结构和一个缓冲区:
double buffer[1000];
typedef struct {
int rows;
int cols;
double* data;
} matrix;
我想要一个可以生成矩阵并从相关缓冲区分配相关内存的宏。然而,我似乎想不出一种方法来保存内部计数器来确定我们目前应该在缓冲区中的位置。理想情况下,宏应该是这样的:
#define alloc_matrix(_rows, _cols) {.rows = _rows, .cols = _cols, .data = &buffer[PTR]}
其中 PTR 是编译时间常数,对于 alloc_matrix 的每次使用,它都会不断变化(按行 * 列增加)。这将允许我在编译时使用 _Static_assert 之类的东西检查所有内容是否适合缓冲区,而不是在运行时检查所有内容。
这可以通过 C 预处理器实现吗?
我尝试过使用 C 预处理器,但似乎找不到在宏中存储状态的方法。
如果您愿意放弃所有矩阵都使用共享数据缓冲区的要求,您可以在这里使用复合文字:
#define alloc_matrix(r, c) {.rows = (r), .cols = (c), .data = (double[(r)*(c)]){0}}
// Allocate immutable matrix with mutable data space
static const matrix MyMatrix = alloc_matrix(3, 4);
但请记住,如果您想要静态存储持续时间,那么这仅适用于外部函数;当函数中定义复合文字时,它将自动具有存储期限。
如果你跳出框框思考,这是可能的。为什么必须分配指向预分配数组的块?
相反,请考虑创建一个只包含
double
数组成员的结构。这样的结构不会有任何填充或对齐问题。随着您添加更多成员,它的大小会增加,所有这些都在编译时进行。
推出臭名昭著但极其灵活的“X 宏”,我们可以在抽象列表中声明所有矩阵/数组:
#define DATA_LIST(X) \
/* name rows cols */ \
X(data1, 5, 7) \
X(data2, 2, 2) \
X(data42, 42, 42) \
现在基于此创建一个结构类型:
typedef struct
{
#define MATRIX_MEMBER_DECL(name, rows, cols) double name [rows][cols];
DATA_LIST(MATRIX_MEMBER_DECL)
} matrix_t;
这扩展到:
typedef struct
{
double data1 [5][7];
double data2 [2][2];
double data42 [42][42];
} matrix_t;
此结构体的实例将恰好占用该数量,不多也不少。我们不需要预先分配任意块并尝试向其中分配指针。
matrix_t matrix;
printf("double items: %zu\n", sizeof matrix / sizeof(double));
printf("Total size: %zu\n", sizeof matrix);
这给出:
double items: 1803
Total size: 14424
(1803 * 8 = 14424,因此没有预测的填充)
您可以像访问任何结构成员一样访问单个矩阵/数组:
matrix.data42[0][0] = 3.1415;
想知道
data42
的行或列大小吗?制作相应的枚举用于查找:
typedef enum
{
#define MATRIX_MEMBER_ROWS(name, rows, cols) name##_##row = rows,
DATA_LIST(MATRIX_MEMBER_ROWS)
} matrix_row_t;
#define MATRIX_GET_ROWS(name) name##_##row
...
printf("%d\n", MATRIX_GET_ROWS(data42)); // prints 42
等等。这都是 100% 纯编译时计算。