【问题标题】:struct member array size based on const int across files基于 const int 跨文件的结构成员数组大小
【发布时间】:2015-06-01 20:56:55
【问题描述】:

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

const int BANANA_ARRAY_SIZE = 10;

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

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

所以,我现在有

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。

【问题讨论】:

  • 您显然只能在 C 的本地范围内进行这种类型的初始化,而不是您正在尝试的全局范围内。 ref 并在同一帖子中:ref2
  • 请阅读我更新的评论,这是我回答的最后一条评论。这对我来说不会发生 gcc-5.1.0.
  • #define BANANA_ARRAY_SIZE 10 char bananas[ BANANA_ARRAY_SIZE ]; const size_t length = BANANA_ARRAY_SIZE;
  • @ryyker:这在本地范围内也不起作用,因为 VLA 必须位于块的顶层,而不是结构内部(但是,有一种使用 flex 数组的方法成员,但这将包括一些沉重的东西。

标签: c arrays struct


【解决方案1】:

在 C 语言中,const 对象不是常量。您不能使用它来声明非 VLA 数组。您的第一个声明不能用 C 语言编译,这使您不清楚“功能正常”的含义。

更多详情请看这里: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;

【讨论】:

  • 我想知道 gcc 是否不符合规范,因为: const int LEN = 12;字符 my_array[LEN]; int main(){ my_array[0] = 'a';返回0;编译得很好......无论如何,我想在c中基本上“这不能按照规范完成”。感谢您的信息!
  • @Phildo:-std=c99c11?这不是“规范”,而是标准。
  • @Phildo:这在任何版本的 C 中都绝对不兼容。你确定你是在 C 模式而不是 C++ 模式下编译吗?在 C++ 中这是合法的。
  • @Olaf 在我之前的评论中使用 - gcc -std=c11 main.c -o a.out 编译代码有效。 -std=c99 同上。
  • @AnT: C99 ISO/IEC 9899:TC3 § 6.6 常量表达式 ...¶ 10 “实现可以接受其他形式的常量表达式”!但是 ¶ 6 说用于数组大小的 整数常量表达式 是整数/枚举/字符常量、sizeof 和浮点常量的组合。 § 6.7.5.2 ¶ 2:“如果标识符是 .. 具有静态存储持续时间的对象,则它不应具有可变长度数组类型。” ¶ 4:“如果 size 是 int~ const~ expr~ 并且元素类型具有已知的常量大小,则该类型不是可变长度数组类型;否则,(它是)。” — 所以 gcc 太过分了!?
【解决方案2】:

您可以使用枚举或#define

enum {
BANANA_ARRAY_SIZE = 10
};

#define BANANA_ARRAY_SIZE 10

【讨论】:

    【解决方案3】:

    您必须为此使用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
    

    【讨论】:

    • 这与 OP 有什么不同?他明确提到他在头文件中使用了extern。问题是关于在头文件中定义结构,同时在 .c 中保留 BANANA_ARRAY_SIZE 定义
    • 我知道使用 extern。我什至有这个问题。问题是“为什么我不能使用 extern const 值来定义数组的长度?”。另外,请参阅我的编辑:使用#defines
    • @Phildo 我完全错过了这个问题,因为它看起来要简单得多,但这是一个很好的问题,我还没有答案。而且,很抱歉,gcc 编译了我刚刚编写的示例,所以无法重现您的问题,您使用的是哪个编译器以及哪个版本?
    • 你不能在 C 中用 gcc 做他想做的事。即使如果编译器会接受这一点,它也最多是实现定义
    【解决方案4】:

    根据 C11 草案 6.6#10,“实现可以接受其他形式的常量表达式。”。

    用 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];
    

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

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


    所以,你必须求助于使用#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 表示数组边界。这就是它的用途(等等)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 2016-05-02
      • 2017-06-11
      相关资源
      最近更新 更多