带有void *指针的_Generic宏不带双参数?

时间:2018-04-14 09:29:36

标签: c macros void

我尝试实现可以​​采用任何数据类型并处理它的_Generic宏,这个示例工作正常,但是使用2个Generic宏,我怎样才能使用一个带有char * int和double的Generic来实现它?

  #include <stdio.h>
  #include <stdlib.h>

  #define puts(x) _Generic((x),              \
    char*:    _puts((void*) x, "str"),       \
    int:      _puts((void*) x, "int")        \
  )

  #define putsd(x) _Generic((x),\
    double: _puts((void*)to_s(x), "float") \
  )


  char*
  to_s(double x)
  {
    char* str = (char *)malloc(1502);
    sprintf(str, "%lf", x);
    free(str);
    return str;
  }

  void _puts(void* d, const char* type)
  {
    if (strcmp(type, "int") == 0){
      printf("%d\n", d);
    } else if (strcmp(type, "float") == 0){
      double res;
      sscanf(d, "%lf", &res);
      printf("%lf\n", res);
    } else {
      printf("%s\n", d);
    }
  }


  int main(void) {
    puts("String");
    puts(1230);
    putsd(13.37);

    return 0;
  }

此外,当我尝试跟随时,我得到错误&#34;&#39; to_s&#39;的参数1的不兼容类型放(&#34;字符串&#34); :

  #include <stdio.h>
  #include <stdlib.h>

  #define puts(x)                              \
    _Generic((x),                               \
        char*:    _puts((void*) x, "str"),       \
        int:      _puts((void*) x, "int"),        \
         double : _puts((void *)to_s(x), "float") \
        )


  char *to_s(double x) {
    char *str = (char *)malloc(1502);
    sprintf(str, "%lf", x);
    free(str);
    return str;
  }

  void _puts(void *d, const char *type) {
    if (strcmp(type, "int") == 0) {
        printf("%d\n", d);
    } else if (type == "float") {
        double res;
        sscanf(d, "%lf", &res);
        printf("%lf\n", res);
    } else {
        printf("%s\n", d);
    }
  }

  int main(void) {
    puts("String");
    puts(1230);
    puts(13.37);

    return 0;
  }

2 个答案:

答案 0 :(得分:2)

您无法将字符串与==

进行比较

更改

if (type == "int") {

if (strcmp(type, "int") == 0) {

float ...

相同

另一方面,你不能传递像123013.39这样的文字的地址,使用中间指针:

int i = 1230;
int *pi = &i;

puts(pi);

然后在你的通用宏中:

#define puts(x)                    \
    _Generic((x),                   \
        char*:    _puts((x), "str"), \
        int *:    _puts((x), "int"),  \
        double *: _puts((x), "float")  \
)

GLib使用一些丑陋的技巧将文字(转换为long)作为指针传递,但这不可移植:Type Conversion Macros

另外,请注意puts是标准库中函数的名称,覆盖此名称不是一个好主意。

使用复合文字修正代码以传递指针:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Puts(x)                \
    _Generic((x),               \
    char *:   _Puts((x), "str"), \
    int *:    _Puts((x), "int"),  \
    double *: _Puts((x), "float")  \
)

static void _Puts(void *d, const char *type)
{
    if (strcmp(type, "int") == 0) {
        printf("%d\n", *(int *)d);
    } else
    if (strcmp(type, "float") == 0) {
        printf("%f\n", *(double *)d);
    } else {
        printf("%s\n", (char *)d);
    }
}

int main(void)
{
    Puts("String");
    Puts((int []){1230});
    Puts((double []) {13.37});   
    return 0;
}

答案 1 :(得分:0)

你错过了泛型的全部要点,你创建了一个完全按照通用做的函数(又名。_puts()。你应该直接在你的泛型中使用正确的函数,加上to_s() free { {1}} ...然后你使用它!调用未定义的行为。并且不要使用stdlib的保留函数名str

一个很好的例子是here

puts()