跨文件基于 const int 构造成员数组大小

struct member array size based on const int across files

所以我想在编译时已知的结构中定义数组的大小。我还希望该数字可用作变量以便以后使用。我有以下内容:

const int BANANA_ARRAY_SIZE = 10;

typedef struct
{
  char bananas[BANANA_ARRAY_SIZE];
  int some_other_stuff;
} banana_struct;

这个功能很好。但是,如果我将它放在包含在多个位置的 .h 文件中,编译器会抱怨 BANANA_ARRAY_SIZE 的重新定义(这是有道理的)。所以我需要将它声明为外部,以便多个编译单元可以知道它。

所以,我现在有

extern const int BANANA_ARRAY_SIZE;

typedef struct
{
  //.. same as before
} banana_struct;

在一个实现文件中我有

const int BANANA_ARRAY_SIZE = 10;

但是现在编译器不再让我定义结构体了

fields must have a constant size: variable length array in structure

有什么方法可以实现我想要的(将数组的长度存储在变量中并用于定义结构)?

编辑:

为了回应使用 #defines 的建议,我宁愿不这样做。

我的问题是关于如何将这个常量值存储在变量中并用于设置结构中数组的长度。如果您需要进一步的理由,假设我需要一个函数,它接受一个指向 int 的指针。无法引用 #define。

为此您必须使用 extern,因此它不是 重新定义的 ,并且您需要在单个 .c 文件中定义一次。

例子

  1. header.h

    extern const int BANANA_ARRAY_SIZE;
    
  2. main.c1

    void banana(void); /* provide a prototype for `banana()' */
    /* A single definition */
    const int BANANA_ARRAY_SIZE = 10;
    
    int main(void)
     {
        banana();
        return 0;
     }
    

1这是为了演示目的,你不要只是在现实生活中添加原型,你必须关心源代码布局并确保原型匹配函数定义等

  1. banana.c

    #include "header.h"
    #include <stdio.h>
    
    void banana(void)
     {
        printf("%d\n", BANANA_ARRAY_SIZE);
     }
    

编译

gcc -Wall -Werror -o banana banana.c main.c    

执行时会打印10.

但我会推荐一个宏,比如

#define BANANA_ARRAY_SIZE 10

然后你甚至可以在编译时定义它

gcc -DBANANA_ARRAY_SIZE=10 a.c b.c d.c -o executable

为了防止重新定义或根本没有定义,公共头文件将包含

#ifndef BANANA_ARRAY_SIZE
#define BANANA_ARRAY_SIZE 10
#endif

您可以使用枚举或 #define

enum {
BANANA_ARRAY_SIZE = 10
};

#define BANANA_ARRAY_SIZE 10

在 C 语言中 const 对象不是 常量。您不能使用它来声明非 VLA 数组。您的第一个声明不能用 C 语言编译,这使您不清楚 "functions fine".

的意思

详情请看这里:Shall I prefer constants over defines?

在您的情况下,您只能使用 #defineenum 常量。如果您还想创建指向该值的指针,则必须根据需要在全局或本地另外声明一个具有相同值的 const 对象。但是您不能在非 VLA 数组声明中使用它。相反,您将不得不使用 #defineenum 常量。例如

// In .h file
#define BANANA_ARRAY_SIZE 10
extern const int BANANA_ARRAY_SIZE_OBJ;

// In .c file
const int BANANA_ARRAY_SIZE_OBJ = BANANA_ARRAY_SIZE;

根据 C11 草案 6.6#10,"An implementation may accept other forms of constant expressions."。

用 gcc 4.8.2 试过:

static const size_t arr_size = 10;  // static does not change anything
static int arr[arr_size];           // dito

gcc -std=gnu11 -Wall test.c

test.c:6:12: error: variably modified ‘arr’ at file scope
static int arr[arr_size];

所以那是行不通的(如果有的话我会感到惊讶)。即使 if id 有效,它也将由实现定义,甚至可能在同一编译器的两个补丁之间发生变化。

有一个明确的原因导致这不起作用,特别是如果 const 具有全局作用域:如果编译的模块在声明中包含 header,则编译器无法知道实际的 常数变量(!)。那么它如何为 .bss 部分中的数组保留 space 或如果给出了初始值设定项(以及 .data 部分中的 alloc space 则能够检查范围? 这将需要链接器的干预,并且会对初始化程序等产生更大的影响。我很确定由于给定的原因,没有编译器会接受它。


因此,您必须求助于 #define:

"array.h":
#define MAX_ARR_LEN 10
extern const size_t max_arr_len;

"array.c":
const size_t max_arr_len = 10;

注意:使用 size_t 作为数组边界。这就是它的用途(以及其他用途)。