使用C语言中的printf()函数重新实现printf()函数

5
我正在制作一个嵌入式Linux项目,我想做一个简单的调试消息库,其中我可以在生产阶段使用预编译指令禁用我的调试消息,并替换为某种类型的数据库日志(将来)。由于va_list,我在重新实现printf()时遇到了问题。这是到目前为止我的代码:
我的源文件:
#include "debug_msgs.h"

#define ENABLE_DEBUG_MSGS   1U

#if ENABLE_DEBUG_MSGS

int print(const char *fmt, ...) {
    int n = -1;
    va_list ap;
    va_start(ap, fmt);
    n = printf(fmt, ap);
    va_end(ap);
    return n;
}

#else

int print(const char *fmt, ...) {
    return 0;
}

#endif

我的头文件:

#ifndef DEBUG_MSGS_H
#define DEBUG_MSGS_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>

int print(const char *fmt, ...);

#endif

我的问题是:

我的实现已经编译通过(我知道这并不表示什么),但当我进行一个简单的测试,比如:

int num1 = 10;
int num2 = 100;
int num3 = 1000;
float floating = 3.14;
char str[] = {"Please work, please"};
int number=-1;
number = print("\nTesting %d %d %d %f %s\n", num1, num2, num3, floating, str);
printf("\nnumber = %d\n",number); //Just to check the return

我收到了以下输出:
Testing -1095005212 100 -1095005212 -0.000002 H*� 

number = 52

补充信息:

这是我的平台信息: Linux mdm9607 3.18.44 #1 PREEMPT Tue Sep 13 19:45:33 UTC 2022 armv7l GNU/Linux

我的编译器信息: arm-oe-linux-gnueabi-gcc

我的 $CFLAGS: -O2 -fexpensive-optimizations -frename-registers -fomit-frame-pointer -MMD -MP

我的 $LDFLAGS:

-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed

LDFLAGS += -lumdp -lumdpcommon
LDFLAGS += -lpthread -lxml2 -lrt
LDFLAGS += -lm

1
你可能想要使用 CPP 宏来代替(或与之结合)调试函数。这是因为如果你有一个这样的调用:debug_print("%d\n",calculate_a_lot());,即使 debug_print 是无操作指令,你仍然需要调用 calculate_a_lot。请参考我的回答:Distributed Computing with PThread Not Working,了解如何使用调试宏以及调试函数。 - Craig Estey
1
你可能想要打开更多的编译器警告,我很惊讶你发布的版本竟然编译通过了。 - CoffeeTableEspresso
@CoffeeTableEspresso 很好的建议,你还有什么编译器警告可以给我建议吗? - Lincoln
1
“-Wall”(打开许多警告)和“-Werror”(将警告转换为错误)是两个很好的标志。稍后,如果您发现“-Wall”给出了任何您不想要的警告,您可以关闭_仅限于该特定警告_。 - CoffeeTableEspresso
1个回答

10

你应该使用带有va_list参数的vprintfvfprintf,而不是printf

#include <stdarg.h>
#include <stdio.h>

int print(const char *fmt, ...) {
    int n;
    va_list ap;
    va_start(ap, fmt);
    n = vprintf(fmt, ap);
    va_end(ap);
    return n;
}

错误的代码编译成功,因为printf作为可变参数函数,在格式字符串后可以接受任何参数类型。但是您可以通过启用更多的编译器警告来避免printf参数的类型不匹配:gcc -Wall -Wextra -Werror至少会抱怨使用非常量格式字符串的printf,并且如果格式字符串是字符串文字,则会执行编译时类型检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接