【问题标题】:What is this macro #define type_string(name) { #name , name }这个宏是什么 #define type_string(name) { #name , name }
【发布时间】:2017-07-16 15:22:39
【问题描述】:

让第一个例子尽可能简单。

我想知道如何应用这个宏;像这里适用于例如printf("%s",macro(arg));

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

#define type_string(name) { #name , name }

int main(void) {

char *hi = "Hello";    
char *arr[]=type_string(hi);
printf("%s\n",type_string(hi));

 return 0;
}

还有其他打印函数名称的方法: 我的最后一个解决方案是这个:

有没有更好的方法来优化这段代码,比如调整__func__

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


// let's declare different functions for calculation
int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int divide(int x, int y);

// let's declare function pointers to different behaviors
//int (*functionPtr_1[4])(int,int);                            // basic form
typedef int (*myFuncDef)(int, int);                       // typedef as the basic form
int do_calculations (int (*functionPtr)(int, int));       // function receives function pointer with two args and returns int
int (*functionFactory(int n))(int, int);



int main() {
    int m = 6;
    int n = 10;
    int res,i;

    int (*functionPtr_arr[4])(int,int) = {&add, &sub, &mul, &divide};

    for(i=0;i<4;i++)
    {
        res=(*functionPtr_arr[i])(4,5);
    }
}

int add(int x, int y) {
int result = x + y;
printf("result for %s op is %d\n",__func__,result);
return result;
}

int sub(int x, int y) {
int result = x - y;
printf("result for %s op is %d\n",__func__,result);
return result;
}

int mul(int x, int y) {
int result = x * y;
printf("result for %s op is %d\n",__func__,result);
return result;
}

int divide(int x, int y) {
int result = x / y;
printf("result for %s op is %d\n",__func__,result);
return result;
}

【问题讨论】:

  • 无论使用宏的上下文如何,它都通过文本替换来工作。在这种情况下,替换的上下文和结果是相当微不足道的。您觉得哪个具体部分难以理解?
  • 如果不知道fns 数组的用途是什么,就不可能回答问题的第二部分。如果您只想“打印函数名称”,那么您可以使用第二个代码。如果目的是创建名称到函数的映射(实际上是 fns 的样子),那么您的第二个版本完全不适用,因为它不这样做。你具体想达到什么目的?不知道没有办法建议如何“优化”代码。
  • @AnT 对于你的第一个评论,这是一个文本替换,我想理解的是我现在明白了这个值被认为是数组中的元素组,所以作者如何初始化在结构数组中,我还了解到在元素数组中我可以用字符串、数字或函数名替换。但是我怎样才能用变量名代替呢?
  • 我还是不明白问题的重点。文本结构相当简单,会产生像{ "fna", fna }{ "fnb", fnb } 等sn-ps,它们后来在数组初始化中充当大括号括起来的初始化器。那么,您真正的问题是什么:文本替换如何工作或数组初始化中大括号封闭的初始化程序如何工作? “用变量名称替换”是什么意思?您到底指的是什么“变量名称”?
  • @AnT 对于您的第二条评论,第二个代码是来自其中一位成员的建议示例,关于如何在我询问____func____ 的地方显示函数名称并将其替换为 for 循环main 函数,而不是替换每个函数。

标签: c string macros


【解决方案1】:

#define FN_RECORD(f) { #f, f } 这个宏的工作原理是将一个变量 f 放入其中,并将该值放入它要替换的内容中。

例如

有函数int abc(void);

FN_RECORD(abc) 放入您的代码将在预处理后替换为{ "abc", abc }# 创建一个字符串。

似乎创建此宏的人打算将其用作 c 字符串形式的函数名称,以及它的函数指针。

【讨论】:

  • 但是如何应用它而不像第一个代码示例那样将其包含在数组中?我试过了,但做不到。
【解决方案2】:

描述宏的注释非常清楚,因此不确定您可能会被什么混淆。

在上下文中,它用于为fns 数组生成初始化程序。所以:

fn_record fns[3] = {                        
    FN_RECORD(fna),
    FN_RECORD(fnb),
    FN_RECORD(fnc) 
};

扩展到:

fn_record fns[3] = {                        
    {"fna", fna},
    {"fnb", fnb},
    {"fnc", fnc} 
};

评论说这是为了节省您的打字时间,但这是一个相当愚蠢的理由 - 它几乎没有节省宝贵的时间。它有用的是确保字符串和函数名匹配以避免可能的错误。

【讨论】:

  • 我试图将这个宏应用到结构之外,但我做不到。
  • @PerchEagle 宏可以在任何地方展开。但是,如果,例如,{"fna", fna} 在这种情况下没有意义,它将无法编译。如果您不知道为什么编译失败,您可以使用gcc -E foo.c 进行编译以查看所有预处理后代码的样子。 (这也将包括所有的标题,所以一开始会有很多麻烦。)
  • @PerchEagle :为什么您希望宏在其预期上下文之外具有任何语法意义?宏不是函数;它们是文本替换,必须在 扩展之后在语法上有效。有时宏具有类似函数的行为——这不是其中之一;在这种情况下,它的函数式语法有些误导。
  • @Ray 为什么会失败?我的意思是我对定义的宏的理解,您可以在代码中的任何位置应用它们。因此,在第一个示例中,作者将它们包含在 struct typedef 数组中!这怎么可能?应用这些以函数名称作为参数的宏的可能位置是什么?
  • @PerchEagle 该宏对原始文本(技术上的标记,但我们暂时忽略它)进行操作并生成其他原始文本。然后编译器就像您刚刚键入了宏生成的文本一样。如果宏生成的代码在 struct typedef 数组中有意义,那么它将在该上下文中工作。
【解决方案3】:

让我们一步一步地分解它。

#define type_string(name) { #name , name }

int main(void) {
    char *hi = "Hello";    
    char *arr[]=type_string(hi);
    printf("%s\n",type_string(hi));
}

编译分两个阶段进行(如果算上链接,则为三个阶段,但我们忽略它)。预处理器和编译器在很多情况下实际上是独立的程序,但编译器会自动运行预处理器。

预处理

首先,我们进行所有预处理。那么让我们看看接下来会发生什么:

char *arr[]=type_string(hi);

令牌hi 被传递给type_stringhi 是一个变量这一事实并不重要。 name 包含 hi,而不是 "Hello"

  • # 是字符串化操作符。由于namehi#name 的计算结果为"hi"

  • name 仅计算为 hi

所以type_string(hi) 作为一个整体计算为{ "hi" , hi },并且该行作为一个整体变为char *arr[]={ "hi" , hi };printf("%s\n", type_string(hi)); 工作方式相同,变为printf("%s\n", { "hi" , hi });

编译

现在预处理已经完成,实际的编译器开始工作了。这是编译器将看到的:

int main(void) {
    char *hi = "Hello";    
    char *arr[]={ "hi" , hi };
    printf("%s\n",{ "hi" , hi });
}

{ "hi", hi } 将评估为char* 的数组;第一个元素隐式指向(常量)字符串文字"hi",第二个元素初始化为当前包含在hi 中的地址,恰好是字符串文字"Hello" 的地址。

当然,这是行不通的; printf("%s\n", { "hi" , hi }) 期待一个字符串并获得一个数组字面量,这在这种情况下是不合法的。

您可以改为使用printf("%s, %s\n", arr[0], arr[1]);,这将打印hi, Hello

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2019-06-10
    • 2018-03-03
    相关资源
    最近更新 更多