C/C++预定义宏、 #line 、#error、 #pragma和泛型选择

文章目录

  • 预定义宏
    • `_ _func_ _`是C语言的预定义标识符
  • #line和#error
  • #pragma
  • 泛型选择(C11)
  • 参考

预定义宏

C标准规定了一些预定义宏:
预 定 义 宏

_ _func_ _是C语言的预定义标识符

C99 标准提供一个名为_ _func_ _的预定义标识符,它展开为一个代表
函数名的字符串(该函数包含该标识符)。那么,_ _func_ _必须具有函数
作用域,而从本质上看宏具有文件作用域。因此,_ _func_ _是C语言的预定
义标识符,而不是预定义宏。

下面程序中使用了一些预定义宏和预定义标识符。注意,其中一
些是C99 新增的,所以不支持C99的编译器可能无法识别它们。如果使用
GCC,必须设置-std=c99或-std=c11。

predef.c程序:

// predef.c -- 预定义宏和预定义标识符
#include <stdio.h>
void why_me();
int main(){printf("The file is %s.\n", __FILE__);printf("The date is %s.\n", __DATE__);printf("The time is %s.\n", __TIME__);printf("The version is %ld.\n", __STDC_VERSION__);printf("This is line %d.\n", __LINE__);printf("This function is %s\n", __func__);why_me();return 0;
}
void why_me(){printf("This function is %s\n", __func__);printf("This is line %d.\n", __LINE__);
}

下面是该程序的输出:

The file is predef.c.
The date is Sep 23 2013.
The time is 22:01:09.
The version is 201112.
This is line 11.
This function is main
This function is why_me
This is line 21.

#line和#error

#line指令重置_ _LINE_ __ _FILE_ _宏报告的行号和文件名。可以这
样使用#line:

#line 1000 // 把当前行号重置为1000
#line 10 "cool.c" // 把行号重置为10,把文件名重置为cool.c

#error 指令让预处理器发出一条错误消息,该消息包含指令中的文本。
如果可能的话,编译过程应该中断。可以这样使用#error指令:

#if _ _STDC_VERSION_ _ != 201112L
#error Not C11
#endif

编译以上代码生成后,输出如下:

$ gcc newish.c
newish.c:14:2: error: #error Not C11
$ gcc -std=c11 newish.c
$

如果编译器只支持旧标准,则会编译失败,如果支持C11标准,就能成
功编译。

#pragma

在现在的编译器中,可以通过命令行参数或IDE菜单修改编译器的一些
设置。#pragma把编译器指令放入源代码中。例如,在开发C99时,标准被
称为C9X,可以使用下面的编译指示(pragma)让编译器支持C9X:

#pragma c9x on

一般而言,编译器都有自己的编译指示集。例如,编译指示可能用于控
制分配给自动变量的内存量,或者设置错误检查的严格程度,或者启用非标
准语言特性等。C99 标准提供了 3 个标准编译指示。

C99还提供_Pragma预处理器运算符,该运算符把字符串转换成普通的
编译指示。例如:

_Pragma("nonstandardtreatmenttypeB on")

等价于下面的指令:

#pragma nonstandardtreatmenttypeB on

由于该运算符不使用#符号,所以可以把它作为宏展开的一部分:

#define PRAGMA(X) _Pragma(#X)
#define LIMRG(X) PRAGMA(STDC CX_LIMITED_RANGE X)

然后,可以使用类似下面的代码:

LIMRG ( ON )

顺带一提,下面的定义看上去没问题,但实际上无法正常运行:

#define LIMRG(X) _Pragma(STDC CX_LIMITED_RANGE #X)

问题在于这行代码依赖字符串的串联功能,而预处理过程完成之后才会
串联字符串。

_Pragma 运算符完成“解字符串”(destringizing)的工作,即把字符串中
的转义序列转换成它所代表的字符。因此,

_Pragma("use_bool \"true \"false")

变成了:

#pragma use_bool "true "false

泛型选择(C11)

在程序设计中,泛型编程(generic programming)指那些没有特定类
型,但是一旦指定一种类型,就可以转换成指定类型的代码。例如,C++在
模板中可以创建泛型算法,然后编译器根据指定的类型自动使用实例化代
码。

C没有这种功能。然而,C11新增了一种表达式,叫作泛型选择表达式
(generic selection expression),可根据表达式的类型(即表达式的类型是
int、double 还是其他类型)选择一个值。泛型选择表达式不是预处理器指
令,但是在一些泛型编程中它常用作#define宏定义的一部分。
下面是一个泛型选择表达式的示例:

_Generic(x, int: 0, float: 1, double: 2, default: 3)

_Generic是C11的关键字。_Generic后面的圆括号中包含多个用逗号分隔
的项。第1个项是一个表达式,后面的每个项都由一个类型、一个冒号和一
个值组成,如float: 1。第1个项的类型匹配哪个标签,整个表达式的值是该
标签后面的值。例如,假设上面表达式中x是int类型的变量,x的类型匹配
int:标签,那么整个表达式的值就是0。如果没有与类型匹配的标签,表达式
的值就是default:标签后面的值。泛型选择语句与 switch 语句类似,只是前
者用表达式的类型匹配标签,而后者用表达式的值匹配标签。
下面是一个把泛型选择语句和宏定义组合的例子:

#define MYTYPE(X) _Generic((X),\
int: "int",\
float : "float",\
double: "double",\
default: "other"\
)

宏必须定义为一条逻辑行,但是可以用 \ 把一条逻辑行分隔成多条物理
行。

在这种情况下,对泛型选择表达式求值得字符串。例如,对
MYTYPE(5)求值得"int",因为值5的类型与int:标签匹配。

下面程序演示了这种用法:

mytype.c程序

// mytype.c
#include <stdio.h>
#define MYTYPE(X) _Generic((X),\
int: "int",\
float : "float",\
double: "double",\
default: "other"\
)
int main(void)
{
int d = 5;
printf("%s\n", MYTYPE(d)); // d 是int类型
printf("%s\n", MYTYPE(2.0*d)); // 2.0 * d 是double类型
printf("%s\n", MYTYPE(3L)); // 3L是long类型
printf("%s\n", MYTYPE(&d)); // &d 的类型是 int *
return 0;
}

下面是该程序的输出:

int
double
other
other

MYTYPE()最后两个示例所用的类型与标签不匹配,所以打印默认的字
符串。可以使用更多类型标签来扩展宏的能力,但是该程序主要是为了演示
_Generic的基本工作原理。

对一个泛型选择表达式求值时,程序不会先对第一个项求值,它只确定
类型。只有匹配标签的类型后才会对表达式求值。

可以像使用独立类型(“泛型”)函数那样使用_Generic 定义宏。

参考

《C Primer Plus》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/146465.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3:print()打印. 2023-11-18

Python3 print ()不换行输出 import random # 导入random for i in range(10):print(random.randint(1,999), end",") #random.randint(1,999)随机返回1-999间任意一个整数,包括1和999 #print()添加end"" 自定义参数&#xff0c;实现不换行输出效果.end的…

ElasticStack日志分析平台-ES 集群、Kibana与Kafka

一、Elasticsearch 1、介绍&#xff1a; Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;Logstash 和 Beats 收集的数据可以存储在 Elasticsearch 中进行搜索和分析。 Elasticsearch为所有类型的数据提供近乎实时的搜索和分析&#xff1a;一旦数据被索引&#…

《向量数据库指南》——TruLens + Milvus Cloud构建RAG深入了解性能

深入了解性能 索引类型 本例中,索引类型对查询速度、token 用量或评估没有明显影响。这可能是因为数据量较小的关系。索引类型对较大语料库可能更重要。 Embedding 模型 text-embedding-ada-002 在准确性(0.72,平均 0.60)和答案相关度(0.82,平均0.62)上优于 MiniLM Embeddin…

Office Word 中的宏

Office Word 中的宏 简介宏的使用将自定义创建的宏放入文档标题栏中的“自定义快速访问工具栏”插入指定格式、内容的字符选中word中的指定文字查找word中的指定文字A&#xff0c;并替换为指定文字B插入文本框并向内插入文字word 表格中的宏操作遍历表格中的所有内容批量设置表…

CTF-PWN-堆- 【off-by-one】

文章目录 堆的off-by-one利用思路Asis CTF 2016 b00ks libc 2.31IDA源码main输入名字creat函数dele函数edit函数print函数reeditor name函数 思路exp思路 堆的off-by-one off-by-one指的是单字节缓冲区溢出&#xff08;off-by-one 是可以基于各种缓冲区的&#xff0c;比如栈、…

解决公网下,k8s calico master节点无法访问node节点创建的pod

目的&#xff1a;解决pod部署成功后&#xff0c;只能在node节点访问&#xff0c;而master节点无法访问 原因&#xff1a;集群搭建时&#xff0c;没有配置公网进行kubectl操作&#xff0c;从而导致系统默认node节点&#xff0c;使用内网IP加入k8s集群&#xff01;如下&#xff…

八股文-TCP的三次握手

TCP协议是一种面向连接、可靠传输的协议&#xff0c;而建立连接的过程就是著名的三次握手。这个过程保证了通信的双方能够同步信息&#xff0c;确保后续的数据传输是可靠和有序的。本文将深入解析TCP三次握手的步骤及其意义。 漫画TCP的三次握手 TCP连接的建立采用了三次握手的…

VSCode 使用CMakePreset找不到cl.exe编译器的问题

在用vscode开发c项目的时候&#xff0c;使用预先配置的CMakePresets.json可以把一些特定的cmake选项固定下来&#xff0c;在配置时直接使用 "cmake --config --preset presetname"就可以进行配置&#xff0c;免去在命令行输入过多的配置参数。 但是在vscode中&#…

Uniapp中的事件处理:uni.emit和uni.on/uni.once

介绍 在Uniapp项目中&#xff0c;事件处理是一种重要的通信方式。uni.emit和uni.on&#xff08;以及uni.once&#xff09;是Uniapp中用于实现组件间通信的两个关键方法。本文将深入介绍这两个方法&#xff0c;探讨它们的优势、劣势&#xff0c;并通过示例代码演示它们的用法。…

C++菜鸟日记2

关于getline()函数&#xff0c;在char和string输入的区别 参考博客 1.在char中的使用&#xff1a; 2.在string中的使用&#xff1a; 关于char字符数组拼接和string字符串拼接方法 参考博客 字符串拼接方法&#xff1a; 1.直接用 号 2.利用append&#xff08;&#xff0…

Django——模型层补充

django中如何开启事务 # 事务的四大特性: # 简称: ACID# A: 原子性事务对数据的修改操作要么同时成功, 要么一个都别想成功(回滚)# C: 一致性事务的执行必然是从一个一致性的状态, 转变到另一个一致性的状态.# I: 隔离性对于并发的事务, 每个事务之间是互相隔离的, 互不影响的.…

如何防止图片抖动

如何防止图片抖动 什么是图片抖动&#xff0c;就是我们加载图片完成之后&#xff0c;图片显示&#xff0c;但是其下方内容会跟着下移&#xff0c;这就造成了图片抖动用户体验不好&#xff0c;我们想即使图片没加载出来&#xff0c;页面上也有一个空白的位置留给图片。 我们要知…

【观察】华为:数智世界“一触即达”,应对数智化转型“千变万化”

毫无疑问&#xff0c;数智化既是这个时代前进所趋&#xff0c;也是国家战略所指&#xff0c;更是所有企业未来发展进程中达成的高度共识。 但也要看到&#xff0c;由于大量新兴技术的出现&#xff0c;技术热点不停的轮转&#xff0c;加上市场环境的快速变化&#xff0c;让数智化…

Nacos 配置中心底层原理(1.X版本)

前言 Nacos 1.X版本 是长轮询 Nacos 2.X版本 是GRPC 长轮询 概念 客户端会轮询向服务端发出一个长连接请求&#xff0c;这个长连接最多30s就会超时&#xff0c;服务端收到客户端的请求会先判断当前是否有配置更新&#xff0c;有则立即返回&#xff0c;如果没有服务端会将这个…

upload-labs关卡9(基于win特性data流绕过)通关思路

文章目录 前言一、靶场需要了解的知识1::$data是什么 二、靶场第九关通关思路1、看源码2、bp抓包修改后缀名3、检查是否成功上传 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不能随意去尚未授…

【cpolar】Ubuntu本地快速搭建web小游戏网站,公网用户远程访问

&#x1f3a5; 个人主页&#xff1a;深鱼~&#x1f525;收录专栏&#xff1a;cpolar&#x1f304;欢迎 &#x1f44d;点赞✍评论⭐收藏 目录 前言 1. 本地环境服务搭建 2. 局域网测试访问 3. 内网穿透 3.1 ubuntu本地安装cpolar 3.2 创建隧道 3.3 测试公网访问 4. 配置…

Netty Review - 从BIO到NIO的进化推演

文章目录 BIODEMO 1DEMO 2小结论单线程BIO的缺陷BIO如何处理并发多线程BIO服务器的弊端 NIONIO要解决的问题模拟NIO方案一&#xff1a; &#xff08;等待连接时和等待数据时不阻塞&#xff09;方案二&#xff08;缓存Socket&#xff0c;轮询数据是否准备好&#xff09;方案二存…

Pyrthon中pandas DataFrame对表格数据选取,修改,切片的实现

set_index()函数 在Python Pandas的数据处理中&#xff0c;set_index是一个非常常用的函数&#xff0c;它的作用就是将DataFrame中的一列或多列作为新的索引。使用set_index函数&#xff0c;可以快速地进行数据的筛选和重组。 如何在pandas中使用set_index( )与reset_index( )…

医院数字化LIS(检验信息系统)源码

临床检验信息管理系统&#xff08;LIS&#xff09;是利用计算机连接医疗设备&#xff0c;通过计算机信息处理技术&#xff0c;将医院检验科或实验室的临床检验数据进行自动收集、存储、处理、提取、传输和交换&#xff0c;满足所有授权用户的功能需求。 一、系统概述 1.LIS&am…

Redis篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、持久化有两种,那应该怎么选择呢?二、怎么使用 Redis 实现消息队列?三、说说你对Redis事务的理解前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,…