【问题标题】:Share sizeof(array) between two modules在两个模块之间共享 sizeof(array)
【发布时间】:2020-06-26 12:19:31
【问题描述】:

我想在两个 .c 模块之间共享 sizeof(array) 的值。数组在文件A中初始化,所以编译器在编译时就知道大小,然后我想在另一个B文件中使用这个数组的大小。

示例:
在 A.c 文件中:

int arr[] = {1, 2, 3};
.
.
.

for (int i = 0; i < sizeof(arr); i++); // that works

在 A.h 文件中:

extern int arr[];

在 B.c 文件中:

#include "A.h"
.
.
.

for (int i = 0; i < sizeof(arr); i++); // here compiler doesn't know size of this arr

有没有办法让它工作?我知道为什么这不起作用,但也许有一个偷偷摸摸的技巧来解决这个问题。

【问题讨论】:

  • 在 A.h:extern int arr[3];
  • sizeof(arr) 不会产生元素的数量。它为arr 生成分配的字节数,如果sizeof(int) == 4,则应为12。
  • 如果需要,请使用@pmg 方式。答案中的所有方法都容易出错,难以维护
  • @P__J__ 但这不满足问题的要求,确定A.c中数组的大小。
  • @RobertSsupportsMonicaCellio 它在两个文件中都有。

标签: c arrays compilation linker


【解决方案1】:

有没有办法让这个工作?我知道为什么这不起作用,但也许有一个偷偷摸摸的技巧来解决这个问题。

不幸的是,这不是很偷偷摸摸,但它确实有效......

some.h

//declare as extern for project global scope
extern int arr[];
extern size_t gSizeArray;

然后在some.c

//define and initialize extern variables in 1 (and only one) .c file, 
int arr[] = { 1,2,3 };
size_t gSizeArray = sizeof(arr)/sizeof(arr[0]);

someother.c 中,包括some.h

#include "some.h"
//you can now see the value of gSizeArray in this file

printf("%zu\n%d,%d,%d\n", gSizeArray, arr[0], arr[1], arr[2]);//should output

3
1,2,3

警告
以这种方式使用 extern 的 是该变量的值可以在一个模块中更改,并且可以在 包含的任何 .c 文件中看到相同的值 some.h

推论
以这种方式使用 extern 的问题是该变量的值可以在一个模块中更改,并且可以在 包含的任何 .c 文件中看到相同的值 some.h.

(或者换句话说,要小心。全局变量,特别是 extern 全局变量可能会有所帮助,但它们也可能很危险。特别是对于代码的维护者,他们不是代码的作者,他们可能不会请注意变量的范围为extern,并在不知情的情况下以不适当的方式使用它。

顺便说一句,关于使用 extern 作用域 in this post,您可能想知道的更多。

【讨论】:

  • 如果你做gSizeArrayconst是安全的,但它仍然有点浪费,而且不像整数常量表达式那样灵活。
  • @PSkocik - 在命名任何具有全局范围的内容时,我会尽量明确,以鼓励未来的维护者了解它的定义位置和方式。但在这种情况下,我确实更喜欢灵活性而不是安全性。
  • @PSkocik - 谢谢!我刚打开编辑器,你抢先了。
  • 如果我错了,请纠正我,some.c 必须在 someother.c 之前编译?
  • 那个 const 改变了游戏规则。
【解决方案2】:

将初始化器设为宏,通过标头共享,然后您可以使用编译器重新计算extern 声明的元素:

//header.h
#define ARR_INIT { 1, 2, 3}
extern int arr[sizeof((int[])ARR_INIT)/sizeof(int)];

//file.c
#include "header.h"
int arr[] = ARR_INIT;

( 在 gcc/clang/tinycc 上,你也可以这样做:

//header.h
#define ARR_INIT (int[]){ 1, 2, 3}
extern int arr[sizeof(ARR_INIT)/sizeof(ARR_INIT[0])];

//file.c
#include "header.h"
int arr[] = ARR_INIT;

这更安全,但不适用于 -Wpedantic,因为标准 C 不允许复合文字作为具有静态存储持续时间的对象的初始值设定项。 )

您也可以通过常规全局共享大小,但这有缺点,因为这样的大小将不再是整数常量表达式,因此在需要的地方(数组大小、位域宽度、案例标签、静态初始化器)。

【讨论】:

    【解决方案3】:

    你可以做到通过声明size 对象(包含arr 的元素数量)和数组arr,以及extern 存储类说明符,以便它们在标题A.h 中具有外部链接。此标头包含在两个 .c 源文件中。

    size 对象的值以及数组arr 的大小(通过其初始化列表)在A.c 中指定,但可以在B.c 中使用。


    A.h 文件:

     #include <stdio.h>     // for size_t.
    
     extern int arr[];
     extern size_t size;
    

    A.c 文件:

     #include "A.h"
     #include <stdio.h>     // for size_t. 
    
     int arr[] = { 1, 2, 3 };
     size_t size = sizeof (arr) / sizeof (arr[0]);
    
     for ( size_t i = 0; i < size; i++ ) 
     {
          arr[i] = arr[i] - 1;
     }
    

    B.c 文件:

     #include "A.h"
     #include <stdio.h>
    
     for ( size_t i = 0; i < size; i++ ) 
     {
          printf("%d\n", arr[i]);
     }
    

    输出:

     0
     1 
     2
    

    旁注:

    • sizeof(arr) 不会产生arr 中的元素数量;它产生分配给整个数组arr 的字节数。由于 arrint 类型的数组,而不是 f.e. char,其中元素的数量等于分配的字节的数量,这个结果与元素的数量不同。

      要获得元素数量,请使用sizeof(arr) / sizeof(arr[0])

    【讨论】:

      【解决方案4】:

      不需要魔法或其他全局变量。

      在 .h 文件中

      extern int arr[3];
      

      然后

      int main(void)
      {
          printf("%zu\n", sizeof(arr)/ sizeof(arr[0]));
      }
      
      

      【讨论】:

      • 问题中的[](而不是[3])暗示OP不想手动跟踪计数。如果这是真的, 需要一点魔法才能在翻译单元之间共享自动计算的计数。
      • 但这是一种不好的做法。更普遍的是如何设计静态全局池内存 - 但是全局[]数组和另一个全局变量的方式不是答案。
      【解决方案5】:

      当你在头文件中说extern int arr[];时,你告诉编译器:

      • 此变量稍后定义。它不是在这里分配的,而是在别处分配的。
      • 此数组的大小未知(不完整)。稍后我定义变量时完成。

      C 使用称为翻译单元 的东西。翻译单元是一个 .c 文件及其包含的所有标题。在您的示例中,A.c + A.h 形成一个翻译单元,B.c + A.h 形成另一个。这些是独立编译的。

      在翻译单元A.c + A.h 中,编译器定义变量并为其指定大小(3 int)。因此,该数组的大小在整个翻译单元中都是已知的。

      在翻译单元B.c + A.h,你永远不会定义变量。编译器只知道数组是在“其他地方”定义的,但它无法知道大小。


      原因是extern 意大利面条编程,其中相同的全局变量在所有地方共享。正确的解决方案是永远不要这样做。改用带有私有封装的声音程序设计。让数组分配到对它有意义的地方。类似这样的东西(愚蠢的例子):

      数组.h

      int    get_array_item (size_t i);
      void   set_array_item (size_t i, int val);
      size_t get_array_size (void);
      

      数组.c

      #include "array.h"
      
      static int arr[] = {1,2,3};
      
      int get_array_item (size_t i)
      {
        assert(i < sizeof arr); // optional error handling
        return array[i];
      }
      
      void set_array_item (size_t i, int val)
      {
        assert(i < sizeof arr); // optional error handling
        array[i] = val;
      }
      
      size_t get_array_size (void)
      {
        return sizeof arr;
      }
      

      在真正的应用程序中,这个“数组”当然是有意义的。

      【讨论】:

        猜你喜欢
        • 2015-10-08
        • 2012-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-06
        • 2017-01-21
        • 1970-01-01
        相关资源
        最近更新 更多