2014-10-10 59 views
3

我正在编写一个程序在ATmega328p上运行 - 尽管它使用的是Arduino引导程序而不是Arduino,但它并不是Arduino,而是裸露的avr-libc(我不认为会影响以下问题虽然)。avr-libc上的fprintf()会立即崩溃

我已经设置了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); 

如果我写信只用fputcfputs然后一切工作正常我的程序。我甚至可以拨打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

您可能会看到是否有一个可以运行它的调试器的模拟器。 – 2014-10-10 20:56:22

+1

步入'fprintf',并“散步”拆卸,直到发生崩溃。然后再执行一次,并且在执行导致崩溃的指令之前,打开注册视图,复制所有寄存器,并在此处发布它们。另外,发布导致崩溃的指令。这可能会为我们提供一些重要的信息。顺便说一句,你可以用'fputs'来做同样的事情,亲眼看看一个人是如何工作的,另一个人是不工作的。 – 2014-10-10 21:27:55

+0

与任何printf函数相关的崩溃使我想到堆栈溢出。尝试增加堆栈大小。 – kkrambo 2014-10-11 14:49:53

回答

0

您正在使用fdev_setup_stream()更新stdout的分配。 的documentation of fdev_setup_stream()明确规定,但:

注: 的标准流不分配将通过fdev_setup_stream进行()。 如果要使用标准流,则这些需要由用户分配。

同一文件指向code example for using stdio without malloc。 代码有看起来很相似,你除了两件事情:

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); 
  • stdout被初始化为这个自定义流:

    1. 自定义流使用宏FDEV_SETUP_STREAM()定义

      stdout = &mystdout; 
      

    我想,你的鳕鱼e正在使用未初始化的流stdout。 “引进到标准IO设备”(www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#details)规定:提供

    标准流标准输入,标准输出,和标准错误,但与C标准相反,由于avr-libc不了解适用的设备,因此这些流在应用程序启动时尚未预先初始化。

    未初始化时,使用stdout的所有函数调用的行为未定义。根据stdout实际指向的位置,某些呼叫可能仍然有效。