首页 > 后端开发 > C++ > 正文

#define INC(a) INC(a ?

Susan Sarandon
发布: 2024-10-22 06:10:31
原创
477 人浏览过

#define INC(a) INC(a ?

这个宏会导致 GCC 崩溃吗?读完你就会有答案

本文的目标是向您介绍 C 语言宏的壮丽世界。

预处理器指令

在 C 中,以 # 开头的行由编译器在编译源文件时解释。这些称为预处理器指令。宏就是其中之一。

小历史点:

C 语言宏是随第一个 C 语言标准引入的,称为 ANSI C(或 C89),
于 1989 年由美国国家标准协会 (ANSI) 标准化。

然而,在此标准化之前,宏已经成为 20 世纪 70 年代使用的经典 C(或 K&R C)语言的一部分
。 最初的 C 编译器由 Dennis Ritchie 为 UNIX 操作系统开发,已经通过预处理器包含了基本形式的宏,允许使用 #define 进行定义。

定义

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);
登录后复制
登录后复制
登录后复制

定义的工作方式非常容易理解:编译器将代码中出现的所有内容替换为定义的值。它使用以下语法 #define 。约定名称为大写字母,值是可选的。

有点像“Ctrl-f 并替换”。

妈妈,宏观

我们可以使用定义来定义可以在代码中使用的函数。

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;
登录后复制
登录后复制
登录后复制

如果或没有如果

我们可以有条件地声明宏。
如果名称已经定义,那么我们执行以下代码。

#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}
登录后复制
登录后复制
登录后复制

在本例中,我使用了 #ifndef,但它也存在:

  • #ifdef
  • #if
  • #其他
  • #elif
#if (X == 1)
#define Y 2
#elif (X == 2)
#define Y "Ami de la bonne blague, bonjour !"
#else
#define Y NULL
#endif /* ! X */

/* ... */

int main(void) {
    #if (X == 1)
    printf("%d\n", Y);
    #elif (X == 2)
    printf("%s\n", Y);
    #else
    printf("%p\n", Y);
    #endif /* ! X */
}
登录后复制
登录后复制

我们喜欢用批量评论来表示 #if 的结束。这是一个可以让您更好地浏览代码的约定。

预定义宏

您可以在前面的示例中看到我使用了关键字 __FUNCTION__ 和 __LINE__。
正如您可以想象的,这些是编译器将替换为正确值的宏。

有一个常见预定义宏的列表。

请注意,有所谓的系统特定宏。

小型非详尽列表:

  • __日期__:2012 年 1 月 14 日
  • __GNUC__:GCC 的主要版本
  • __时间__:15:12:18
  • __INCLUDE_LEVEL__:包含的深度从0
  • 开始
  • __BASE_FILE__:当前文件的名称

走向无限,超越论证

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);
登录后复制
登录后复制
登录后复制

在这里,我们可以看到我们生成了可变参数宏,在创建日志时特别有用。
(即使使用 printfs 生成日志不是一个好主意。)

X-宏

为此,我们必须创建一个外部文件,通常命名为 *.def,尽管没有约定。

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;
登录后复制
登录后复制
登录后复制
#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}
登录后复制
登录后复制
登录后复制

这种宏非常有用。我必须承认,它很少在源代码中找到,但它允许您修改程序的操作,而无需修改源代码。有趣的是,它经常用于创建内核。它允许您生成全局结构,例如 IDT 和 GDT。

存在的问题

注意:首先快速澄清一下,宏是很棒的工具,但你必须小心。你绝对不应该使用这种类型的宏:

#if (X == 1)
#define Y 2
#elif (X == 2)
#define Y "Ami de la bonne blague, bonjour !"
#else
#define Y NULL
#endif /* ! X */

/* ... */

int main(void) {
    #if (X == 1)
    printf("%d\n", Y);
    #elif (X == 2)
    printf("%s\n", Y);
    #else
    printf("%p\n", Y);
    #endif /* ! X */
}
登录后复制
登录后复制

举个例子:MIN(2 5, fibo(25))

问题#1

MIN(2 5, fibo(25)) => (2 5

这里的问题是计算优先级。编译器将首先执行比较,然后执行加法,因此为 2 (1)。我们通过使用宏参数添加括号来纠正此问题。

// Ici, l'opérateur ## est l'opérateur de concaténation
#define DEBUG_PRNTF(fmt, ...) printf("LOG" ## fmt, __VA_ARGS__);
登录后复制

由于您永远不知道用户将传递什么作为参数,因此请始终在参数上加上括号。

问题#2

MIN(2 5, fibo(25)) => (2 5

我们注意到编译器做了一个愚蠢而令人讨厌的替换,这意味着我们将计算 fibo(25) 两次。我让你想象一下它是否是一个递归实现。

为了解决这个问题,我们在 if 之前声明一个中间变量。

有用的宏

// color.def
X(NC, "\e[0m", "No Color", 0x000000) 
X(BLACK, "\e[0;30m", "Black", 0x000000) 
X(GRAY, "\e[1;30m", "Gray", 0x808080) 
X(RED, "\e[0;31m", "Red", 0xFF0000) 
X(LIGHT_RED, "\e[1;31m", "Light Red", 0xFF8080) 
X(GREEN, "\e[0;32m", "Green", 0x00FF00) 
X(LIGHT_GREEN, "\e[1;32m", "Light Green", 0x80FF80) 
X(BROWN, "\e[0;33m", "Brown", 0xA52A2A) 
X(YELLOW, "\e[1;33m", "Yellow", 0xFFFF00) 
X(BLUE, "\e[0;34m", "Blue", 0x0000FF) 
X(LIGHT_BLUE, "\e[1;34m", "Light Blue", 0xADD8E6) 
X(PURPLE, "\e[0;35m", "Purple", 0x800080) 
X(LIGHT_PURPLE, "\e[1;35m", "Light Purple", 0xEE82EE) 
X(CYAN, "\e[0;36m", "Cyan", 0x00FFFF) 
X(LIGHT_CYAN, "\e[1;36m", "Light Cyan", 0xE0FFFF) 
X(LIGHT_GRAY, "\e[0;37m", "Light Gray", 0xD3D3D3) 
X(WHITE, "\e[1;37m", "White", 0xFFFFFF)
登录后复制

在那里我们玩得很开心

在这里,这纯粹是为了好玩而编写的多余代码。我不一定建议您在代码中使用这些宏。
我只是在享受乐趣(人生中的一件好事)。

一辆免费汽车

typedef struct {
    const char *name;        
    const char *ansi_code;  
    const char *description;
    unsigned int rgb;      
} Color;

#define X(NAME, ANSI, DESC, RGB) { #NAME, ANSI, DESC, RGB },
Color colors[] = {
    #include "color.def"
};
#undef X

#define X(NAME, ANSI, DESC, RGB) printf("%s (%s) = %s\n", #NAME, DESC, #RGB);
void print_colors() {
    // Bien entendu, on pourrait itérer sur la structure créée mais c'est une illustration
    #include "color.def"
}
#undef X
登录后复制

我会让你用一点 -fsanitize=address 进行测试。真的很疯狂。我们甚至可以看到 auto_free 函数的改进,它将结构名称的字符串作为参数来进行切换。

争取时间

更多的 chill 函数,我们只计算函数的执行时间。对于基准测试非常有用。

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);
登录后复制
登录后复制
登录后复制

定义错误

小 X 宏,它将宏作为参数并对其进行扩展。

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;
登录后复制
登录后复制
登录后复制

自动测试生成

在这里,我们实际上用宏生成整个函数,因为 C 没有限制。我也是?

#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}
登录后复制
登录后复制
登录后复制

实时FM

现在是时候总结一下了。我们看到了很多很酷的东西。如果您有兴趣,您可以自由地自己探索宏。还有很多东西值得一看。
所以,结论:RTFM

PS: 至于标题,宏不是递归的,它们仅以深度 1 扩展,在我们目前的情况下,GCC 将对 INC 进行隐式声明并崩溃。

以上是#define INC(a) INC(a ?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!