【问题标题】:C macro returning type of variableC 宏返回变量的类型
【发布时间】:2016-06-19 07:42:12
【问题描述】:

是否可以创建一个宏函数,其返回值是预定义的 c 变量数据类型之一?比如:

#include <stdio.h>
#define IND_I_ 0
#define IND_F_ 1
#define INT_FORMAT_ "%i"
#define FLOAT_FORMAT_ "%f"
// (Of course the following macros do not make the desired jobs)
// FORMAT_ macro would be used for the variable format:
#define FORMAT_( ind_ )( (ind_) == IND_I_ ? FOR_INT_ : FOR_FLOAT_ )
// VAR_TYPE_ macro would be used for 
// defining variable types and for the casting of variables:
#define VAR_TYPE_( ind_ ) ( (ind_) == IND_I_ ? int : float )

int main( void )
{
  VAR_TYPE_( IND_I_ ) first_var = 123; //here I want: int first_var = 123;
  VAR_TYPE_( IND_F_ ) second_var = 345.789;
  //Instead of:
  //printf( "int variable = " "%i" "\n", first_var );
  //I would use:
  printf( "int variable = " FORMAT_(IND_I_) "\n", first_var );
  printf( "float variable = " FORMAT_(IND_F_) "\n", second_var );
  printf( "truncated real variable = "  INT_FORMAT_ "\n", (VAR_TYPE_(IND_I_))second_var );
  return 0;
}

【问题讨论】:

    标签: c function types macros


    【解决方案1】:

    抱歉,这在 C 系列中是不可能的。 (在具有更强大的宏系统的语言中可能的,例如 Common Lisp 和 Rust。)

    宏唯一能做的就是文本替换。所以你的

    #define VAR_TYPE_( ind_ ) ( (ind_) == IND_I_ ? int : float )
    #define IND_I_ 0
    VAR_TYPE_( IND_I_ ) first_var = 123;
    

    扩展到

    ( (0) == 0 ) ? int : float ) first_var = 123;
    

    这是一个语法错误。没有办法让它评估 ?: 表达式。

    VAR_TYPE_ 的参数扩展为文字零、一等时,您可以做一件事:

    #define VAR_TYPE_(ind_) VAR_TYPE__(ind_)
    #define VAR_TYPE__(ind_) VAR_TYPE__##ind_
    typedef int VAR_TYPE__0;
    typedef float VAR_TYPE__1;
    // etc
    

    ...但是如果您要这样做,您可能希望允许ind_ 成为任意整数常量表达式,这将不起作用。你会得到类似的东西

    VAR_TYPE_sizeof(int)==4?0:2
    

    在扩展中,你会回到语法错误。

    (Psst:每次你在括号里面加上空格,上帝就会杀死一只小猫。)

    【讨论】:

    • @zwol,您认为使用#if、#else、#elif 指令可以解决我的问题吗?
    • @Olaf 它演示了“可以做到”和“不能做到”之间的确切界限。它不打算在生产代码中使用。
    • 来自 C11 的那个邪恶的 _Generic 构造可以做到这一点。虽然格式字符串连接不起作用,至少不是以任何直接的方式。
    • @doynax 我自己从来不需要使用_Generic,但如果我正确阅读C11,它只能用于调度 on 类型,而不是选择一种类型。也就是说,它可以做到(typeof x == y) ? expr_A : expr_B,但不能做到(boolean expression) ? type_A : type_B
    • _Generic 有点糟糕,因为它不区分兼容类型。
    【解决方案2】:

    宏 r 只是文字替换,所以你不能这样做。 使用 c++ 11 / 14,自动类型和外流句柄将适合。

    【讨论】:

    • “使用 C++”不是专门针对 C 提出的问题的答案,是吗?
    • @MOehm 是的,不是。
    【解决方案3】:

    简短的回答是:不。

    你想达到什么目标?
    为什么需要在 C 中灵活输入?或许你应该转向 Java 或 Python。

    在您的示例中,您已经有了类型信息,因此使用宏来替换特定于类型的字符串文字是多余的。

    如果你想从外部控制变量的类型,我强烈反对,你可以设置宏替换并通过标题注入它们或直接在编译器的命令行中指定它们.

    演示示例(请不要在家里这样做):

    #include <stdio.h>
    #include <stdlib.h>
    /* // eg.
    #define TEH_TYPE double
    #define TEH_TYPE_FMT "%f"
    #define TEH_TYPE_ATO atof
    */
    // Either, or see command line below.
    /*
    #define TEH_TYPE int
    #define TEH_TYPE_FMT "%d"
    #define TEH_TYPE_ATO atoi
    */
    
    int main(int argc, char **argv) {
        TEH_TYPE v;
        if(argc > 1)
        {
            v = TEH_TYPE_ATO(argv[1]);
            printf("So your thingie is " TEH_TYPE_FMT "\n", v);
        }
        return 0;
    }
    

    然后您可以将其编译为gcc -DTEH_TYPE=int -DTEH_TYPE_FMT='"%d"' -DTEH_TYPE_ATO=atoi main.c -o main

    但同样,请不要。我很惭愧写下来。

    【讨论】:

    • 非常感谢您的简短回答。我在这里写的代码当然是我想做的事情的代表部分。我想知道我在问题中解释的效果是否可以实现。
    猜你喜欢
    • 2013-09-28
    • 1970-01-01
    • 2012-05-17
    • 2018-08-30
    • 2012-05-04
    • 2023-01-29
    • 2012-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多