当我找到微控制器的头文件时,我正在浏览它,
#define DEFA(name, address) __no_init union \
{ \
struct \
{ \
volatile unsigned char name##_L; \
volatile unsigned char name##_H; \
}; \
struct \
{ \
volatile unsigned short name##L; \
volatile unsigned short name##H; \
}; \
__ACCESS_20BIT_REG__ name; \
} @ address;
我在这里有多个问题,
有人,请向我解释一下这种代码的安宁性,所有内容都取决于这段代码,并且所有内容都直接或间接使用此#define。 :(
答案 0 :(得分:2)
您可以将大多数内容放入宏中,它们大多只是文本替换(尽管在逐个令牌级别的令牌上)。但是,将typedef和变量声明放在宏中是不好的做法,除非没有其他选择,否则应避免。
它将粘贴令牌并创建新的预处理器令牌。在这种情况下,它将创建成员变量名称。如果您使用DEFA(foo,0)
,将获得名为foo_H
和foo_L
的成员。
值得注意的是,如果将字段仅命名为H和L,则此特定宏可能会更好。为什么有人要键入reg.foo_H
而不是foo.H
?使用_L
和L
后缀来区分8位访问和16位访问也不是一个好主意。
同一代码使用的某些自定义类型。为什么不知道为什么它们在“ 20位”和32位结构之间有结合?我不知道。
非标准扩展名。通常,它用于在特定地址分配变量,在这种情况下就是这种情况。可能您有一个内存映射的硬件寄存器,并且该宏应该是此类寄存器的通用声明。
同样值得注意的是,联合语法不是标准的C。您需要命名联合。自C11以来,匿名结构都是标准C,但是我怀疑这是来自现代编译器。
总体来说,非常糟糕的代码。您可以在芯片/工具供应商提供的微控制器寄存器映射中找到一种非常典型的垃圾代码。不符合ISO C或MISRA-C。
答案 1 :(得分:1)
- 我不知道我们可以在#define语句中使用并集和结构。编译器如何解释它们?
定义语句只是宏。它们不是由编译器而是由预处理器解释的。宏中定义的那部分代码只是复制粘贴到您调用/使用该宏的任何地方。如果包含有效的C / C ++代码,则在完成预处理程序后,还将在下一步中进行编译。
- “名称## _ L”和“名称## L”是什么意思??,尤其是“ ##”。
是的,我曾经对此##
感到惊讶。这是令牌串联。基本上,您可以使用它生成“以编程方式”的变量/函数名称。例如,您有
#include <stdio.h>
#define concat(a, b) a##b
int main(void)
{
int foobar = 1;
printf("%d", concat(foo, bar));
return 0;
}
会打印1
,因为它会连接 foo
和bar
一起形成foobar
。
- 什么是“
__ACCESS_20BIT_REG__ name
”?
__ACCESS_20BIT_REG__
似乎是一个实现定义的宏,可能在代码的其他地方定义了。保留__
的双下划线,后跟一个大写字母(以便您的uC制造商可以使用它们)。
- 这个新的“ @”符号是什么,我在Google上搜索了有关该符号的信息,但在任何地方都找不到与@符号相关的东西,有人说这不是C标准,这是真的吗?是什么意思?
这个也让我难过。我认为这不是合法的C。
编辑:
实际上,关于第4点,即@
标记,我在Google上进行了更多搜索,找到了这个stackoverflow question。
答案 2 :(得分:0)
我认为解释这段代码的最佳方法是尝试一个示例:
那么,定义DEFA(name, address)
的结果是什么?
使用定义,例如DEFA(myName, myAddress)
预处理器创建以下代码行:
__no_init union
{
struct
{
volatile unsigned char myName_L;
volatile unsigned char myName_H;
};
struct
{
volatile unsigned short myNameL;
volatile unsigned short myNameH;
};
__ACCESS_20BIT_REG__ myName;
} @ myAddress;
现在就您的问题: