我正在编写一个程序在ATmega328p上运行 - 裸avr-libc
而不是Arduino,虽然它确实使用Arduino引导程序而不是串行(我不认为这会影响以下问题)。
我已设置stdout
以希望明显的方式写入UART:
void uart_putc(char c)
{
// Turn LFs into CRLFs
if(c == '\n')
uart_putc('\r');
while(!(UCSR0A & _BV(UDRE0)))
;
UDR0 = c;
}
static int _putc(char c, FILE *_)
{
uart_putc(c);
return 0;
}
...
fdev_setup_stream(stdout, &_putc, NULL, _FDEV_SETUP_WRITE);
如果我现在只使用fputc
和fputs
编写程序,那么一切正常。我甚至可以致电snprintf()
将格式化的字符串呈现为char buffer[16]
,然后将fputs()
呈现出来;这些都很好。
fputs("Hello, world\n", stdout); /* works fine */
char buffer[16];
snprintf(buffer, sizeof buffer, "Hello, %s\n", "world");
fputs(buffer, stdout); /* also works fine */
但是,当我尝试执行真正的fprintf()
到stdout
时,程序会崩溃并重新启动ATmega:
fprintf(stdout, "Hello, %s\n", "world");
在此处输出初始H
之前,它会立即崩溃。
当fprintf()
和snprintf()
都可以正常工作时,有人可以提出可能会遗漏的内容,这会阻止fputs()
工作吗?
答案 0 :(得分:0)
您正在使用fdev_setup_stream()
更新stdout
的分配。
documentation of fdev_setup_stream()
明确指出:
注意: fdev_setup_stream()不会对标准流进行任何分配。 如果要使用标准流,则需要由用户分配这些流。
同一文件指向code example for using stdio without malloc。 除了两件事之外,那里的代码与你的代码非常相似:
使用宏FDEV_SETUP_STREAM()
定义自定义流:
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
stdout
已初始化为此自定义流:
stdout = &mystdout;
我认为,您的代码使用的是未初始化的stdout
流。 "标准IO设施简介" (www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#details)声明:
提供了标准流stdin,stdout和stderr,但与C标准相反,由于avr-libc不了解适用的设备,因此这些流在应用程序启动时尚未预先初始化。
未初始化时,使用stdout
的所有函数调用的行为未定义。根据{{1}}实际指向的位置,某些调用可能仍然有效。