【问题标题】:Generic argument for fprintf in CC 中 fprintf 的通用参数
【发布时间】:2014-01-19 05:08:29
【问题描述】:

我正在编写一个使用 fprintf 函数将数据保存到 C 文件中的函数。但是,这需要占位符作为其参数之一。 例如:%s 代表字符串,%d 代表整数... 如果数据类型是泛型的,即使用该函数的程序员可以将我正在写入文件的变量的数据类型设置为任何他想要的,我该怎么办? 谢谢!

【问题讨论】:

  • 将你写的内容发布到“将数据保存到文件的函数”中
  • 格式化打印 (printf) 很有用,因为它将数据“转换”为字符串(它“获取”其字符串表示形式)。但是它不能知道它是什么类型的数据,所以由你来指定它。这里的“你”也可以简单地表示你的函数的“调用者”。

标签: c file generics save printf


【解决方案1】:

由于只有在运行时才能知道数据的类型,所以您必须:

  • 在运行时生成 fprintf 函数使用的格式字符串, 或

  • 在多个硬编码格式字符串之间进行选择以传递给 fprintf。

这两个选项之间的选择可能取决于您必须处理多少种不同的类型,和/或您在运行时如何知道占位符参数的类型。

【讨论】:

    【解决方案2】:

    您可以使用w+ 打开您的文件,以便以二进制格式写入您的数据

    那么你可以使用fwrite()直接以二进制形式写入数据,供fread()稍后读取。

    【讨论】:

    • 不过,我怀疑他想要数据的“字符串表示”,而不是“原始”数据。
    • 我正在尝试这个语句,但是程序崩溃了:fwrite((scan->Item.data), sizeof(Item),1, filepointer);其中 Item 是一个结构,其中包含一个名为 data 的 void 指针,而 scan 是一个指向节点的指针(我使用的是链表)
    • 我认为我的问题在于第三个参数。
    • @user3126802 在新主题中分享您的代码问题,以获得有关此崩溃的帮助
    【解决方案3】:

    C 不支持泛型,除了 void* 我认为, 我一直在做一个让 C 有点通用的小项目。 你可以通过设置类型的参数之一来做你想做的事 说 0 表示字符串 和 1 表示整数

    然后做一个 if-else 语句,然后对每个单独使用 printf。

    int print (FILE f,void*x,int 类型) { 如果(类型==0) 返回 fprintf(f,"%s",(char*)x); 别的 返回 fprintf(f,"%d",*(int*)x); }

    【讨论】:

    • 这个想法是正确的(调用者必须指定数据的类型,以便它可以选择正确的方式将其表示为字符串),但建议的实现(if-else)不是一样好,据我说。
    • 我已经编辑并添加了一个小示例,您可以将其转换为具有良好通用意义的 switch 语句;)
    • 使用符号名称而不是数字(0 是字符串,0 是整数,我怎么记得?)是首选...然后,int 类型的示例看起来错误,% d 期望值,而不是指向的指针!
    【解决方案4】:

    可以尝试以下方法:

    在写入时使用struct 了解数据类型

    typedef enum { String, Int, Char} datatype;
    struct record{
      datatype dt;
      void* data;
    };
    
    int myfprintf(FILE* stream, struct record* rec){  
    
      switch(rec->dt){
         case Char:     return fprintf(stream, "%c", *((char*)(rec->data)));
         case Int:      return fprintf(stream, "%d", *((int*)rec->data));        
         case String:   return fprintf(stream, "%s", (char*)rec->data);     
         //....     
         default:       return fprintf(stream,"%s", "Error");
      }                                
    } 
    

    然后使用myprintf传递流和record类型的数据

    或者,您也可以以类似的方式使用union

    使用C11,您可以执行以下操作:-(取自here):

    #define printf_dec_format(x) _Generic((x), \
        char: "%c", \
        signed char: "%hhd", \
        unsigned char: "%hhu", \
        signed short: "%hd", \
        unsigned short: "%hu", \
        signed int: "%d", \
        unsigned int: "%u", \
        long int: "%ld", \
        unsigned long int: "%lu", \
        long long int: "%lld", \
        unsigned long long int: "%llu", \
        float: "%f", \
        double: "%f", \
        long double: "%Lf", \
        char *: "%s", \
        void *: "%p")
    
     #define fprint(stream, x) fprintf(stream,printf_dec_format(x), x)
    
    
     fprint(stdin,(char *)"P0W"); // for string literal
    

    【讨论】:

      【解决方案5】:

      C 没有通用数据类型,因此必须创建一个。

      typedef enum {
        Generic_int, Generic_float, Generic_double, Generic_string
      } Generic_Type;
      
      typedef struct {
        Generic_Type type;
        union {
          int i;
          float f;
          double d;
          char *s;
        // other types
        } u;
      } Generic;
      
      void Generic_printf(Generic *G) {
        switch (G->type) {
          case Generic_int:
            printf("%d", G->u.i);
            break;
          case Generic_float:
            printf("%.*e", FLT_DECIMAL_DIG, G->u.f);
            break;
          case Generic_double:
            printf("%.*e", DBL_DECIMAL_DIG, G->u.d);
            break;
          case Generic_string:
            printf("\"%s\"", G->u.s);  // Enclose string in quotes
            break;
            // other
        }
      }
      

      【讨论】:

      • C11 有 _Generic 所以 switch 语句和结构是多余的。
      • @ShinTakezou 有趣的是,将 C11 视为现在的 2014 年。
      • @self _Generic 很有趣,但通常目的地还需要类型提示以供以后阅读。类似于 "" 之类的字符串,是 FP 类型中的指数。还有floatdouble 应该被写入不同的精度。这一切都导致printf() 不太通用,因为参数的数量可能不同。我确实看到_Generic 仍然可以使用,感谢您指出。
      猜你喜欢
      • 2013-07-26
      • 1970-01-01
      • 1970-01-01
      • 2017-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-29
      • 2021-06-15
      相关资源
      最近更新 更多