使用void *指针(在运行时推断类型的类型)将未知/混合类型传递给printf()

时间:2016-05-16 17:45:02

标签: c pointers casting printf

我正在尝试将混合类型传递给SELECT * FROM temp t WHERE col1 = 100 OR NOT EXISTS (SELECT 1 FROM temp WHERE col1 = 100); 。在实际代码中(在底部),我还传递格式占位符,以便printf()知道如何格式化。

虽然意外地将这些printf()指针直接用作值调用,但我发现我的代码没有按预期工作。

所以我创建了一个测试程序,搜索并探索,直到我想出了这个解决方案。

void*

但是我不希望硬编码#include <stdbool.h> #include <stdint.h> #include <string.h> #include <stdio.h> #include <stdlib.h> void test1(void* a) { printf("value: %d\n", *(int*)a); } void test2(void* a) { printf("value: %f\n", *(float*)a); } int main(int argc, char** argv) { int* aip = &(int){1}; test1(aip); int ai = 1; test1(&ai); float af = 1.75; test2(&af); return 0; } *(int*)解除引用和转换,但实际上写的是这样的:

*(float*)

void test(void* a) { printf("value: %VARIES\n", a); } 被传递到VARIES并连接到最终的格式化程序字符串。

实际功能如下:

test()

我的解决方法是使用void fn(void* value, char* fmtChar) { char fmtHelper[50]; // fill fmtChar in formatter string's %s placeholder snprintf(fmtHelper, sizeof(fmtHelper), "value : %s\n", fmtChar); // actually print value varying argument printf(fmtHelper, value); } / switch语句,并以编程方式确定转换和格式化程序占位符。

2 个答案:

答案 0 :(得分:2)

如果您要定位当前的C(C11),则可以使用带有宏的类型泛型表达式来创建类型泛型函数:

#include <stdio.h>

void print_int(int x) {
    printf("an int: %d\n", x);
}

void print_double(double x) {
    printf("a double: %f\n", x);
}

#define print(X) _Generic((X),             \
                     float: print_double,  \
                     double: print_double, \
                     default: print_int    \
                 )(X)

int main(void) {
    print(1);   // an int: 1
    print(1.0); // a double: 1.00000
}

答案 1 :(得分:0)

此解决方案使用vprintfva_list宏,因此在预处理源时会解析它们。

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

void print(char* msg, char* fmtChars, ...) {
    // format string and write the result to fmtHelper
    // %s is replaced with the value placeholder types
    // (fixed length for simplicity)
    char fmtHelper[50];
    snprintf(fmtHelper, sizeof(fmtHelper), "%s; value 1: %s, value 2: %s\n", msg, fmtChars, fmtChars);

    va_list args;
    // treat all parameters _after_ this named as variable arg
    va_start(args, fmtChars);
    vprintf(fmtHelper, args);
    va_end(args);
}

int main(void) {
    char* msg = "Test";
    int in1 = 1;
    int in2 = 2;
    float fl1 = 4.21;
    float fl2 = 5.89;
    print(msg, "%f", fl1, fl2);
    print(msg, "%d", in1, in2);
}

这是@rici在评论部分给出的提示。