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

news2024/11/28 14:46:02

文章目录

  • 预定义宏
    • `_ _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.coloradmin.cn/o/1216157.html

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

相关文章

无线WiFi安全渗透与攻防(十二)之WPA-自动化渗透WPA加密

WPA-自动化渗透WPA加密 WPA-自动化渗透WPA加密WPA-自动化渗透WPA加密 ip a1.开启监听模式 airmon-ng start wlan02.指定密码破解 wifite --dict passwd.txt --dict:</

11月编程语言排行榜出炉:C#超越Java已成定局!

TIOBE最新的编程语言排行榜刚刚出炉了&#xff0c;本月Java依然大幅下跌3.63%&#xff0c;C#本月上涨3.4%&#xff0c;C#和Java仅相差0.7%。 就像网友评论说的&#xff1a;Java成于互联网的兴起&#xff0c;败于互联网的衰落。 一直以来我也都是从事互联网行业、主要是电商行业…

分享一个图像轮播效果

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 话不多说&#xff0c;先看效果&#xff1a; 根据图片的播放&#xff0c;页面背景会被替换为当前图片。 老规矩&#xff0c;源码自己拿…

Mysql-体系结构

MySQL体系结构 1). 连接层 最上层是一些客户端和链接服务&#xff0c;包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程 池的概念&#xff0c;为通过认证安全接入的客…

【第2章 Node.js基础】2.7 Node.js 的流(一)可写流

&#x1f308;可写流 &#x1f680;什么是可写流 可写流是对数据被写入的目的地的一种抽象。 所有可写流都实现了 stream.Writable类定义的接口。 可写流的例子包括&#xff0c;也都是实现了可写流接口的双工流 客户端的 HTTP 请求、服务器的HTTP 响应、fs 的写入流、zlib…

VC6.0 添加CMarkup文件,程序编译不成功

报错信息 Generating Code... Linking...Creating library Release/Iodevcfg.lib and object Release/Iodevcfg.exp ItemConfigDlg.obj : error LNK2001: unresolved external symbol "public: __thiscall CMarkup::~CMarkup(void)" (??1CMarkupQAEXZ) ItemConfigD…

免费最强下载工具IDM,没有之一

IDM(Internet Download Manager)下载工具是我见过的最强下载工具&#xff0c;没有之一。主要以下特点&#xff1a; 下载程度超快实时检测下载行为下载任何文件探测视频下载地址&#xff0c;几分钟下载高清视频可多进程下载&#xff0c;可多线程下载 IDM官网地址&#xff1a;下…

《C++ Primer》第9章 顺序容器(二)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 9.3 顺序容器操作&#xff08;P305&#xff09; 9.3.1 向容器中添加元素&#xff08;P305&#xff09; 使用push_back 除 array 和 forward_list 外&#xff0c;每个顺序容器都支持 push_back &#xff1a…

MTK联发科MT8766核心板 4G智能模块安卓开发板方案定制

MT8766 是一款基于 MTK 平台工业级高性能、可运行 android12.0 操作系统的 4G智能模块,三款模块硬件是相互兼容&#xff0c;支持 LTE-FDD&#xff08;CAT-7&#xff09;/LTE-TDD&#xff08;CAT-7&#xff09;/WCDMA/TD-SCDMA/EVDO/GSM 等多种制式&#xff1b;支持 WiFi5 802.1…

(Matalb分类预测)WOA-BP鲸鱼算法优化BP神经网络的多维分类预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分程序&#xff1a; 四、完整代码数据使用手册下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matalb…

IDEA 快捷键汇总

目录 1、altinsert 2、ctrl/ 3、altenter 4、alt回车 5、ctrlD 6、ctrlaltL 7、ctrl点击 8、alt左键向下拉 9、ctrlaltv 10、ctrlaltwint 1、altinsert 快速创建代码&#xff0c;可以快速创建类中get set tostring等方法 2、ctrl/ 单行注释 3、altenter…

linux套接字-Socket

1.概念 局域网和广域网 局域网&#xff1a;局域网将一定区域内的各种计算机、外部设备和数据库连接起来形成计算机通信的私有网络。广域网&#xff1a;又称广域网、外网、公网。是连接不同地区局域网或城域网计算机通信的远程公共网络。IPInternet Protocol&#xff09;&#…

实用篇-ES-DSL查询文档

数据的存储不是目的&#xff0c;我们希望从海量的酒店数据中检索出需要的信息&#xff0c;这就是ES的搜索功能 官方文档: https://elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl。DSL是用来查询文档的 Elasticsearch提供了基于JSON的DSL来定…

SaaS与PaaS平台的区别

目录 一、前言 二、SaaS化与PaaS化平台的区别 三、PaaS化的低代码平台更胜一筹 PaaS优势&#xff1a; 支持PaaS服务的低代码平台 1.私有化部署&#xff0c;为数据安全保驾护航 2.业内领先技术&#xff0c;为开发强势赋能 3.超强集成能力&#xff0c;系统对接无忧 4.源代码交付&…

openEuler 系统操作 Docker Compose 容器化部署 Redis Cluster 集群的节点添加、删除和可视化监控

容器化部署 Redis Cluster 集群的节点添加、删除和可视化监控 Redis Cluster 集群回顾openEuler 系统查看端口是否被占用Redis Cluster 验证Redis CLI 客户端命令验证Redis GUI 工具验证宿主机安装 RedisInsightDocker 容器化部署 RedisInsight 添加集群节点启动 Reids 扩容服务…

接口自动化测试面试题

前言 前面总结了一篇关于接口测试的常规面试题&#xff0c;现在接口自动化测试用的比较多&#xff0c;也是被很多公司看好。那么想做接口自动化测试需要具备哪些能力呢&#xff1f; 也就是面试的过程中&#xff0c;面试官会考哪些问题&#xff0c;知道你是不是真的做过接口自动…

【Spring】 Spring中的IoC(控制反转)

以往在定义业务层实现时&#xff0c;在指定具体地Dao时候需要具体地定义出其实现&#xff1a; public class BookServiceImpl implements BookService{private BookDao bookDao new BookDaoImpl();public void save(){bookDao.save()} }public class BookDaoImpl implements …

python连接redis库

在自动化过程中&#xff0c;如果需要动态获取某个数据时&#xff0c;需要连接redis数据库。下面来详细介绍下如何操作。 redis这个库是python自带的&#xff0c;直接import导入即可,如下; import redis 1. redis 地址和端口&#xff0c;端口一般都是默认的6379,只需要换下地…

第08章 面向对象编程(高级)

一 关键字&#xff1a;static class Circle{private double radius;public Circle(double radius){this.radiusradius;}public double findArea(){return Math.PI*radius*radius;} }创建两个Circle对象&#xff1a; Circle c1new Circle(2.0); //c1.radius2.0 Circle c2new C…

python如何批量创建文件与文件夹

目录 一、引言 二、批量创建文件 1、使用os模块 2、使用pathlib模块 三、批量创建文件夹 1、使用os模块 2、使用pathlib模块 四、注意事项 五、总结与展望 一、引言 在Python中&#xff0c;我们经常需要创建文件和文件夹来存储和管理数据。批量创建文件和文件夹可以大…