我正在开发一个嵌入式应用程序,它使用库与SPI NAND存储器芯片连接。提供的库使用打印功能,作为应用程序开发人员,我必须覆盖我的特定平台。
例如,他们在代码中广泛使用函数printf_
。
我重新定义它,以便通过串行接口打印打印功能
#define printf_(...) serial.printf(__VA_ARGS__)
它工作正常,但在此平台上,您需要为换行提供回车符(" \ r")。所以现在,当调用库时,格式化很糟糕。
我想追加一个" \ r"到提供给打印功能的任何内容的末尾。喜欢
#define printf_(...) serial.printf(__VA_ARGS__##"\r")
显然这不起作用。
我真的不熟悉,并且很难理解C语言中的可变函数,所以如果我能弄清楚这一点,这将为我提供一点学习机会,或者至少我会学习如果这是不可能的。
我也无法使用va_list
和vsprintf
来包装该函数,因为我的平台不支持此功能(我宁愿在宏中重新定义它,因为个人表演/风格选择。
有办法做到这一点吗?
答案 0 :(得分:1)
也许你可以在调用serial.printf后输出'\r'
?
#define printf_(...) do { serial.printf(__VA_ARGS__); serial.printf("\r"); } while(0)
答案 1 :(得分:0)
我同意其他用户的说法,你在 LF之后你的CR的要求是非常奇怪的,我怀疑你是CRLF,而不是LFCR。无论如何,我会帮助您完成将CR附加到字符串的原始要求。
在单线程宏中执行此操作将非常困难。或者,您可以使用看起来很讨厌的多行宏:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define printf_(format, args...) \
do { \
int _len_orig = strlen(format); \
/* strlen doesn't consider newline. Check for that. */ \
if ( format[_len_orig] == '\n' ) \
_len_orig++; \
\
/* len_orig + 2 to make space for null terminator and '\r' */ \
unsigned _new_size = _len_orig + 2; \
char* _new_str = calloc(_new_size, 1); \
strncpy( _new_str, format, _len_orig ); \
_new_str[_new_size-2] = '\r'; \
\
/* Print out the raw hex of the string to prove it worked */ \
int _i; \
for( _i = 0; _i < _new_size; _i++) \
printf("%02x ", _new_str[_i]); \
printf("\n"); \
free(_new_str); \
} while(0)
int main(){
char* str = "@@@@\n";
printf_( str );
return 0;
}
在我的宏中,我没有使用你的serial.printf函数,而是制作了一些简短的代码,打印出连接字符串的十六进制值,以证明逻辑有效。
要求宏显示为C预处理器的单行。在每个宏行的末尾添加\
会转义换行符。
gcc allows for named arguments in your macro。这里,format
描述了您通常传递给printf的格式字符串,args...
是&#34;其他所有&#34;的变量参数名称。你会传入printf。我在这个例子中没有引用args,但你肯定想在你的最终代码中修改我的例子以包含它。您对printf的调用看起来像serial.printf( _new_str, args);
多行宏是一种令人讨厌的东西,你需要做一些技巧才能让它们作为人类程序员的正常功能出现。需要在do-while is nicely discussed here中包含宏。链接页面适用于C ++,但它也适用于C.
如果你复制我的代码,编译并运行它,这就是输出:
[clipp@h2ologin3:~]$ ./a.out
40 40 40 40 0a 0d 00
此处,此ASCII转储向我们显示复制了4个@
个符号,然后是\n
,\r
,最后是\0
。
还有一个强有力的例子,可以将其写为内联C函数。你说你的系统不支持va_list等所以如果这是真的,那么宏可能是唯一的选择。
QED。