&引用;“节类型冲突”;根据GCC 4.8.2中的宏定义

&引用;“节类型冲突”;根据GCC 4.8.2中的宏定义,c,arduino,C,Arduino,如果在内联函数中调用宏,则会出现“节类型冲突”。 在WWW上找不到关于这个错误的任何信息 宏的目的是提供一个宏来处理Arduino闪存中保存的字符串(只是一个侧面信息)。 如果函数不是内联的,那么一切都很好。原因可能是什么 #undef PROGMEM #define PROGMEM __attribute__(( section(".progmem.data") )) #undef PSTR /* need to define prog_char in avr-gcc 4.7 */ #if

如果在内联函数中调用宏,则会出现“节类型冲突”。 在WWW上找不到关于这个错误的任何信息

宏的目的是提供一个宏来处理Arduino闪存中保存的字符串(只是一个侧面信息)。 如果函数不是内联的,那么一切都很好。原因可能是什么

#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))

#undef PSTR
/* need to define prog_char in avr-gcc 4.7 */
#if __AVR__ && __GNUC__ == 4 && __GNUC_MINOR__ > 6
typedef char prog_char;
#endif
/* Need const type for progmem - new for avr-gcc 4.6 */
#if __AVR__ && __GNUC__ == 4 && __GNUC_MINOR__ > 5
#define PSTR(s) (__extension__({static const prog_char __c[] PROGMEM = (s); \
                                  (const prog_char_t *)&__c[0]; }))
#else
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); \
                                  (prog_char_t *)&__c[0]; }))
#endif
代码:

错误为:“println_p(PSTR(“坏的变量表”);”

编辑: 在两个派生类中调用PSTR()会导致相同的问题。
我认为这是一个编译器错误,它会导致未定义的行为

试试:
PROGMEM静态常量prog\u char\uu c[]
。奇怪的是,我发现属性必须在声明之前,但不确定您的版本实际上做了什么。这很可能就是问题所在

或者:节类型是存储值的Local memory节的属性。我想这是链接器报告的。PROGMEM部分默认为空载(这对于本部分来说是有意义的)。但是,由于初始化的原因,编译器要求节与之相反,从而导致错误。即使不是这样,我也会在这方面寻找问题

一些补充意见:

  • 使用标准类型,不要依赖内置类型的大小
  • 小心“char”。仅用于实际字符,不依赖于其签名。如果您必须关心不同的类型(uint8\u t或int8\u t),则更合适
  • `#“undef”宏不是在使用之前,而是在使用之后(如有必要)。否则,意外的重新定义可能会在没有警告的情况下通过。这些错误可能很难调试!在标题中使用防护装置
  • 在微控制器中,常数的正确性至关重要,所以要明智地使用它。不要避免常量,即使这需要更多的努力(直到你获得更多的经验)。这不仅可以在编译时检测常见缺陷,还可以保存RAM和(甚至可能)闪存,因为非常量变量存储在RAM中,初始化值存储在闪存中
  • 请勿在custon代码中使用
    \uuuuuu
    -前缀。这些应该保留给编译器和工具链的系统库)。不过,您可以将其用作后缀(但为什么在示例中??)
  • 避免打字。初学者代码中的大多数强制转换实际上是不必要的,或者是界面设计不好的症状。基本上:如果不必为函数指定参数的类型,则不需要类型转换。(是的,有例外——这就是为什么我称之为基本规则,而不是法律)
  • 一般来说:使用编译器提供的所有帮助。嵌入式调试并不是很有趣

试着删除
PROGMEM
,看看这是否有区别。还要检查代码中是否只有一个PSTR()调用。请注意,根据标准,“所有以下划线和大写字母或另一个下划线开头的标识符始终保留供任何使用。”因此,宏将
\u c
用作标识符会产生未定义的行为。在实践中,您通常可以不使用保留标识符,但是,如果GCC将
\u c
定义为相关范围内的一个宏(由于保留了它,它可以自由地这样做),那么所有形式的破坏都可能随之发生。检查预处理受影响标题的结果可能会有所启发:
GCC-E AP\u Progmem\u AVR.h
@John:\u c命名不是问题。重命名无法解决此问题。@dgrat:
\uuu c
根据发布的消息,似乎仍然会导致后续错误(此问题必须有另一条消息)。我创建了一个最小的演示。只有在内联函数中调用PSTR函数时,才会发生错误。这是一个编译器错误吗?不确定,我在ARM上使用了原始的4.7.2,实际上还没有使用AVR。但我不这么认为。我仍然不明白为什么4.6和它的前身之间会有区别<代码>常量实际上是标准的。顺便说一句,如果只是针对Flash和RAM:通常情况下,gcc会将常量变量(sic:这就是
const
C
中实际所说的)放入
.const
部分,默认情况下,该部分会链接到Flash中。但这可能与AVR的外部harward体系结构不同(我使用的ARMs和MSP430具有与大多数现代CPU相同的外部冯·诺依曼体系结构)。回答不错,但我不同意关于stdint类型的评论。声明您自己的类型以提供有关含义的提示是绝对正确的。毕竟,这就是为什么我们有像
size\u t
这样的类型,以及
和friends中的所有其他类型。但是,即使您想使用标准类型,这里正确的类型应该是
char
,而不是
uint8\u t
,因为字符串实际上包含字符。@DarkDust:我同意,我的答案可能有点不完整。我实际上也使用size_t,当然还有typedef(实际上很多)。我在编辑中澄清了这一点。顺便说一句:我们谈论的是裸机嵌入式编程,所以我不希望
sys/types.h
存在,其他大多数头文件(独立/非托管环境)也不存在。将PROGMEM放在声明前面没有帮助。
inline void test() {
    hal.console->println("AP_Common tests\n");
    hal.console->println_P(PSTR("AP_Common tests\n") );
    hal.console->printf_P(PSTR("AP_Common tests\n") );
}

void setup(void)
{
  test();
}

void loop(void)
{
    // do nothing
}
AP_HAL/utility/BetterStream.h:53:57: note: in definition of macro 'printf_P'
 #define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__)
                                                         ^
output_debug.h:13:26: note: in expansion of macro 'PSTR'
   hal.console->printf_P( PSTR("{\"t\":\"s_cmp\",\"h\":%.1f}\n"),
                          ^
AP_Progmem/AP_Progmem_AVR.h:25:56: note: '__c' was declared here
 #define PSTR(s) (__extension__({static const prog_char __c[] PROGMEM = (s); \
                                                        ^
AP_HAL/utility/BetterStream.h:53:57: note: in definition of macro 'printf_P'
 #define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__)
                                                         ^
AP_test.ino:60:27: note: in expansion of macro 'PSTR'