【问题标题】:Filling an integer array from global variables then returning it from a function in C从全局变量中填充一个整数数组,然后从 C 中的函数返回它
【发布时间】:2014-04-30 01:02:41
【问题描述】:

有许多全局变量,例如 someglobalvalue1、someglobalvalue2 等,它们是从我正在开发的应用程序的不同部分动态更新的。在我目前正在处理的部分中,我需要将这些变量收集到一个整数数组中。因为在不同的组中有很多这些变量,所以我有单独的函数,如 GetGroupOne()、GetGroupTwo() 等,将全局变量插入数组并将其返回给主函数。我将此页面用作如何从函数返回 int 数组的指南:http://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm

例如:

int main() {
   int *array;
   array = GetGroupOne();
   /* do stuff with array */
   return 0;
}

int * GetGroupOne() {
  static int array[GROUP_ONE_LENGTH] = { someglobalvalue1, someglobalvalue2, someglobalvalue3 };

  return array;
}

所以,尝试编译它(顺便说一下,我仅限于 C90 编译器)得到这个错误:

尝试使用 const 初始化变量时出现“初始化元素不是常量”错误

所以,我确实找到了Error "initializer element is not constant" when trying to initialize variable with const 和其他似乎暗示我试图做的事情,使用全局初始化,是不可能的。所以我硬着头皮做了这个:

int * GetGroupOne() {
  static int array[GROUP_ONE_LENGTH];
  array[0] = someglobalvalue1;
  array[1] = someglobalvalue2;
  array[2] = someglobalvalue3;
  /* etc... */

  return array;
}

现在,这工作,但它非常丑陋,看着它伤害了我的灵魂。特别是因为有多个组,其中一些有超过一百个条目,所以我必须将每个全局单独插入到数组中。我知道如何在高级语言中处理这个问题,但是 C 对我来说仍然有点神秘。但我认为必须有一些更好的方法来处理这个问题。任何人都可以将我推向正确的方向吗?

谢谢。

【问题讨论】:

  • 为什么你的程序设计得如此糟糕,以至于它有数百个全局变量?
  • 静态变量每次都初始化。并且您的静态数组包含值。因此,最好坚持使用您的解决方案 2 或阅读 David 的解决方案。但是一个好的设计不需要(或至少很难)需要全局变量。
  • 为什么不以数组开头?
  • 要扩展 Paul 的建议,您可以将全局变量定义为数组的成员 :: int array[3]; ... #define someglobalvar1 array[0] ...
  • Ooga - 我无法回答这个问题,我没有设计它。 Paul - 当我没有在我的代码中声明全局变量并且无法控制它时,我不清楚如何创建一个全局数组。

标签: c arrays


【解决方案1】:

撇开我自己对需要数百个全局变量的设计的痛苦不谈,至少有一种方法可以改善实现的外观,即使用具有可变长度参数列表的函数。它看起来像这样(未经测试):

#include int * CompileIntegerArray( int *dest, unsigned int count, ... ) { int *put = dest; va_list 参数列表; va_start(参数列表,计数); for( ; count != 0; --count ) { *put++ = va_arg(arglist, int); } va_end(参数列表); 返回目的地; } ... int * GetGroupOne() { 静态整数数组[GROUP_ONE_LENGTH]; 返回 CompileIntegerArray(数组,GROUP_ONE_LENGTH, 一些全局值1, 一些全局值2, 一些全局值3 ); }

意识到你正在做的事情很糟糕。至少,每当组更改长度时,您必须更新长度并确保在对 CompileIntegerArray 的调用中使用正确数量的变量,否则可能会在代码中引入延迟堆栈炸弹。

这种方法当然会对性能产生一些(次要的)影响,并且一些编译器可能会因函数调用的数百个参数而窒息。

[编辑添加替代]

您还可以做另一件事,它可以稍微改善外观,但仍然可以更轻松地更改数组元素的顺序。它有点快,并且不依赖于单独的函数来处理数组。这也将使您有机会进行一些错误检查。使用预处理器:

#define _el(x) 数组[索引++] = x; int * GetGroupOne() { 静态整数数组[GROUP_ONE_LENGTH]; 整数索引 = 0; _el(一些全局值1) _el(一些全局值2) _el(someglobalvalue3) 如果(索引!= GROUP_ONE_LENGTH){ 放(“嘎嘎!”); 退出(1); } 返回数组; }

【讨论】:

  • 哦,我知道了。不幸的是,我无法控制具有数百个全局变量的部分。我明天试试,谢谢!
  • 我还要添加一个静态标志,这样你每次运行只能经历一次这个戏剧
  • @MattMcNabb 我猜该实现会定期调用 GetGroupOne 以获取全局状态的更新“视图”。如果可以选择大规模更改实现,我有点喜欢 Daniel 的解决方案,即返回一组指向全局变量的指针。或者更好的是像“struct GroupOne { int *value1; int *value2; }” 这样您就可以通过名称而不是索引来找到您要查找的内容。然后就可以隐藏所有的全局变量,只暴露组。
  • 我使用了您的替代解决方案。它工作得很好,看起来更好。谢谢你。一个问题:这里的“el”是什么的缩写/首字母缩略词?只是好奇你为什么选择这个名字。
  • @mrrrow "el" 暗示您在每次调用宏时设置的数组元素。
【解决方案2】:

一种选择是让您的静态数组包含指向全局变量的指针(确实算作编译时常量):

int **get_group_one(void)   // (void) instead of () is important
{
// note the `const`, your system will love you for it
// could also add a compile-time test that you actually do have GROUP_ONE_LENGTH entries
static int *const array[GROUP_ONE_LENGTH] = { &global0, &global1, &global2 };

    return array;
}

然后通过宏访问您的全局变量

#define G1(n) ( *(get_group_one()[n])  )

您可以添加一些错误检查来避免范围错误的未定义行为,如果您尝试 G1(n) 其中n 超出范围,那么您可以访问一个虚拟变量,或者调用一个错误处理程序等。

如果您的编译器支持内联函数,那么它会比宏更简洁。

顺便说一句,你有什么理由不能让你的全局变量一开始就放在一个数组中?

【讨论】:

  • 对不起,我不明白你的问题,为什么我不能把我的全局变量放在一个数组中。这就是我想要做的,把它们放在一个数组中。你到底是什么意思,首先把它们放在一个数组中?声明全局变量的地方不是我的代码,我无法控制。
  • 我选择了 David 的解决方案,因为它更易于阅读,没有指向指针的指针(这是一个我还没有完全理解的概念),并且不需要 & 运算符(更容易阅读),但感谢您提供替代方案。等我理解了指针更好的时候再回过头来作为例子来学习。
  • “首先将它们放在一个数组中”,我的意思是在文件范围内拥有int globals_array[GROUP_ONE_LENGTH];,而不是单独的变量someglobalvalue1someglobalvalue2 等。
  • 但是我仍然需要在某个时候将单独的变量放入数组中......我需要存储在来自程序不同部分的全局变量中的数据,我不需要控制。
  • 一个数组变量。我的最后一段建议使用这个变量数组而不是单独的变量。 (尽管您刚刚解释过您的程序结构不允许这样做)。
猜你喜欢
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 2021-10-01
  • 2011-06-16
  • 2014-07-18
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
相关资源
最近更新 更多