【问题标题】:Configurations variables removed by compiler编译器删除的配置变量
【发布时间】:2021-03-13 20:31:22
【问题描述】:

我正在尝试定义一组全局变量来配置我的设备,大约 10 个在专用的 .c 文件中,将在编译时定期更改(根据设备要求),我希望这些放在这个单独的文件中,以便可以轻松更改它们。然后在我的程序中的各种文件中调用这些变量。并且从不改变只读取。问题是我的编译器(用于 PIC MCU 的 XC8)没有定义该变量,因为它只能在文件中看到该变量的一次使用,即使在整个程序中使用 extern 调用它也是如此。

config.h

unsigned int Global_A;
unsigned int Global_B;
void config(void);

config.c

void config(void)
{
   unsigned int Global_A=987;
   unsigned int Global_B=123;
}

prog_a.h

extern unsigned int Global_A;
extern unsigned int Global_B;
unsigned int var_A;
void prog_a(void);

prog_a.c

unsigned int var_A=0;
void prog_a(void);
{
   var_A=Global_A+Global_B;
}

main.c

#include config.h
#include prog_a.h

void main(void)
{
   while(1)
   {
      config();
      prog_a();
   }
}

因此,等效的 var_A 始终为 0,因为编译器已经取消了 config.c,因为它看不到再次调用的变量。

我假设答案对于那些更精通的人来说非常明显,但我在网上找不到任何东西。之前在文件中使用 extern 和 globals 之前,我没有遇到任何问题。但我可能只是从根本上错误地使用它,所以请随意指责我。

提前致谢。

p.s 如果不是很明显,这是一个示例代码来说明我的问题。

【问题讨论】:

  • 我不太明白这个问题,但我可以说在h 文件中定义 变量通常不是一个好主意。您可以在标题中使用extern 声明它们。
  • 您是否真的使用config.c 源文件构建,并链接到从它创建的目标文件?您如何构建您的程序?
  • MPLABX 自动构建和生成链接器

标签: c pic mplab xc8 mcu


【解决方案1】:

您的全局变量都是int 类型,那么为什么不直接使用#define

将文件config.h更改为

#define Global_A 789    
#define Global_B 123

您实际上不必声明任何 int 变量来保存这些值,此外,它们将是 const 并且不可修改。


这就是我们“过去”的做法,但在过去的一两年里,我看到越来越多的人实际上将这些配置值存储在外部文本文件中

它可以是 .INI,也可以是 XML 或 JSON 等等,这取决于您。

您只需创建不同的文件,例如 Singapore.iniParis.iniAuckland.ini 等,每个文件都包含一个键/值对。

例如

time_zone = X
population = Y

等等等等

然后,在 main 的开头,读取文件并存储值 - 但不是在全局变量中,这些天是 frowned upon。将它们读入 config.c 本地的变量中,并让 config.c/h 提供方法来读取它们的值,例如 GetTimeZone()GetPoulation()

不要担心任何代码大小或运行时间影响,因为任何体面的编译器都会in-line这些函数调用。

在外部文本文件中读取“全局”配置值的一个优点是您只需构建您的软件一次。您不需要为每个配置重新构建并拥有一个可执行文件,这是您目前正在走的路。

首先,只需编辑文本文件或提供新文件,即可更轻松地测试您的软件(尤其是自动化测试)。

此外,由于您只有一个可执行文件,您可以将其发送给所有您的用户/客户,并为每个用户/客户提供量身定制的配置文件。您只需更改配置文件即可完全控制和更改软件的功能。您可能需要考虑一下。

【讨论】:

    【解决方案2】:

    使用extern 关键字,有必要声明一次变量(最好在头文件中)定义一次在对变量可见的.c 文件中声明声明。这就对了。 extern 定义的变量是必要的,#include 是发生声明语句的头文件。

    还请注意,在 全局 范围内(即不在函数中)定义 extern 变量也很重要。

    config.h:

    #include "prog_a.h"
    //unsigned int Global_A;
    //unsigned int Global_B;
    void config(void);
    

    main.c

    #include config.h
    #include prog_a.h
    ...
    //suggest defining these here:
    unsigned int Global_A=0;//define outside of function
    unsigned int Global_B=0;
    ...
    

    config.c

    #include "prog_a.h"
    ...
    
    void config(void)
    {
       Global_A=987;
       Global_B=123;
    }
    

    【讨论】:

    • 好的,是的,这就是问题所在,我刚刚删除了“config.c”中的声明,所以它按原样在 config.h 中声明,并且纯粹在 config.h 中定义,只需删除“unsigned int”,奇怪的是它根本没有标记多重定义错误,编译时没有警告。
    • @Josh - 打开编译器警告?
    • config.c 中的定义不会导致多定义警告或错误,因为它们在块范围内定义了新的标识符。
    • 编译器是 XC8 for PIC,编译器警告已开启。
    • config.h 中的定义,由于 config.h 包含在多个源文件中,因此出现在多个翻译单元中,实际上是 暂定定义,C 标准允许 C根据他们的选择来解决。许多 Unix 附属的编译器和链接器,包括在最近版本之前默认的 GCC,将这些暂定定义合并为一个定义。所以我不希望这些工具会出现错误消息。
    【解决方案3】:

    您的函数配置在函数范围内声明了两个新变量(它们的名称隐藏了全局变量的名称)。它们不存在于它之外的任何地方,并且为它们分配值没有任何作用。如果您的目标是初始化全局变量,则需要这样做:

    // config.h
    extern unsigned int Global_A;
    extern unsigned int Global_B;
    void config(void);
    
    // config.c
    unsigned int Global_A;
    unsigned int Global_B;
    void config(void) {
       Global_A=987;
       Global_B=123;
    }
    

    【讨论】:

    • 当然。我假设这是一个精简的示例,并且这些值实际上是作为参数传递给 config 或计算的。或者在调用 config() 之前有一些代码依赖于它们尚未初始化。
    猜你喜欢
    • 1970-01-01
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多