【问题标题】:Header variable turn to zero头变量归零
【发布时间】:2020-06-14 12:20:40
【问题描述】:

我正在使用 STM32F103 和 Keil 作为编译器。这是我的摘要代码: 有一个像 abc.h 这样的头文件,而 abc 文件有一个静态变量。 abc.h 是这样的:

static uint8 a;

在另一个名为 abcd.h 的头文件中有一个函数,它改变了 a 的值。 abcd.h头文件就是这样的。

include "abc.h"

void foo()
{
    a = 0x0A;
}

我的问题是: 当我在主函数“a”中调用“foo”函数时,即使我在“foo()”函数中将“a”变量分配给 0x0A,也会变为零。顺便说一句,如果我用 extern 定义“a”变量并且问题不会发生。我的意思是“a”是获取 0x0A 值。

有没有人帮我看看为什么会出现这个问题。

【问题讨论】:

  • 您有两个不同的对象,它们具有不同的范围,使用相同的标识符。在代码中的几个位置尝试printf("adress of object identified with a: %p\n", &a);,其中任何标识符a 都在范围内。使用extern 是生成单个对象的正确方向。
  • 我不想将变量初始化为 extern,因为将变量初始化为 extern 时。它变成了一个全局变量,我不想要它。我期待另一个解决方案。
  • @alptekinkarabacak 如果同一个变量需要被多个 C 文件中的代码修改,则该变量是全局变量。一个变量不能既是全局的又不是全局的。
  • @alptekinkarabacak :我假设“全球”,您的意思是“外部链接”?如果您希望能够从不同的编译单元访问相同的变量,您需要外部链接。

标签: c variables header stm32 keil


【解决方案1】:

一些经验法则:

  • 永远不要声明全局变量。 (extern 个)
  • 切勿在头文件中声明变量。

static 变量根据定义不是全局的,但可以是“文件范围” - 也就是说,对在其中声明它们的文件可见。或者更准确地说,在 translation unit 中可见,它们被声明在其中,一个翻译单元意味着一个特定的 .c 文件和 .c 文件包含的所有头文件。

因此,如果您在标头中声明 static 变量,该变量包含在两个不同的 .c 文件中,那么您最终会得到该变量的多个本地副本。如果幸运的话,您会收到链接器错误,但链接器也可能会尝试一些内部“名称修改”。 static的真正含义是防止其他文件访问该变量。

最好的解决方案是使用 setter/getter 函数:

// abc.h
#ifndef ABC_H // always use "header guards"
#define ABC_H

uint8_t get_a (void);
void set_a (uint8_t n);

#endif

-

// abc.c

#include "abc.h"

static uint8_t a;

uint8_t get_a (void) 
{ 
  return a; 
}

void set_a (uint8_t n) 
{ 
  a = n; 
}

在绝大多数情况下,您应该这样做。应该避免使用extern,但在极少数情况下你必须使用它,然后像这样使用它:

// abc.h
#ifndef ABC_H // always use "header guards"
#define ABC_H

extern uint8_t a;

#endif

-

// abc.c
#include "abc.h"

uint8_t a;

【讨论】:

  • 哦,非常感谢,我正在考虑这个问题并就此再写一个问题。
  • @lundin“从不声明”——我认为从不定义。头文件中的extern ..... 可以
  • @P__J__ 这是最后的手段。对const 变量执行一些操作是可以的,对硬件寄存器内存映射也可以执行此操作。除此之外......你需要一些非常特殊的实时要求来证明“extern-spaghetti”的合理性。大多数情况下,extern 的存在仅仅是由可疑的设计引起的。
猜你喜欢
  • 1970-01-01
  • 2019-08-07
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 2012-02-26
  • 2011-08-30
相关资源
最近更新 更多