当前位置: 首页 > wzjs >正文

织梦 网站地图 样式郑州网站seo服务

织梦 网站地图 样式,郑州网站seo服务,网站添加搜索关键字,云南做网站要多少钱1、概述 __is_constexpr是Linux内核中一个重要的宏,用于在编译时检测一个表达式是否为常量表达式。它由Martin Uecker开发,并在2018年4月通过commit 3c8ba0d61d04引入Linux内核v4.17版本。 通过这个宏的设计,我们可以看到Linux内核开发者对…

1、概述

__is_constexpr是Linux内核中一个重要的宏,用于在编译时检测一个表达式是否为常量表达式。它由Martin Uecker开发,并在2018年4月通过commit 3c8ba0d61d04引入Linux内核v4.17版本。

通过这个宏的设计,我们可以看到Linux内核开发者对编译器和C语言特性的深入理解和巧妙运用。

1.1、内核源码

/// https://elixir.bootlin.com/linux/v6.12/source/include/linux/compiler.h#L248
/** This returns a constant expression while determining if an argument is* a constant expression, most importantly without evaluating the argument.* Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de>** Details:* - sizeof() return an integer constant expression, and does not evaluate*   the value of its operand; it only examines the type of its operand.* - The results of comparing two integer constant expressions is also*   an integer constant expression.* - The first literal "8" isn't important. It could be any literal value.* - The second literal "8" is to avoid warnings about unaligned pointers;*   this could otherwise just be "1".* - (long)(x) is used to avoid warnings about 64-bit types on 32-bit*   architectures.* - The C Standard defines "null pointer constant", "(void *)0", as*   distinct from other void pointers.* - If (x) is an integer constant expression, then the "* 0l" resolves*   it into an integer constant expression of value 0. Since it is cast to*   "void *", this makes the second operand a null pointer constant.* - If (x) is not an integer constant expression, then the second operand*   resolves to a void pointer (but not a null pointer constant: the value*   is not an integer constant 0).* - The conditional operator's third operand, "(int *)8", is an object*   pointer (to type "int").* - The behavior (including the return type) of the conditional operator*   ("operand1 ? operand2 : operand3") depends on the kind of expressions*   given for the second and third operands. This is the central mechanism*   of the macro:*   - When one operand is a null pointer constant (i.e. when x is an integer*     constant expression) and the other is an object pointer (i.e. our*     third operand), the conditional operator returns the type of the*     object pointer operand (i.e. "int *"). Here, within the sizeof(), we*     would then get:*       sizeof(*((int *)(...))  == sizeof(int)  == 4*   - When one operand is a void pointer (i.e. when x is not an integer*     constant expression) and the other is an object pointer (i.e. our*     third operand), the conditional operator returns a "void *" type.*     Here, within the sizeof(), we would then get:*       sizeof(*((void *)(...)) == sizeof(void) == 1* - The equality comparison to "sizeof(int)" therefore depends on (x):*     sizeof(int) == sizeof(int)     (x) was a constant expression*     sizeof(int) != sizeof(void)    (x) was not a constant expression*/
#define __is_constexpr(x) \(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

2、工作原理

该宏的实现主要依赖三个关键机制:

  1. C语言条件运算符的类型推导规则
  2. 空指针常量的定义
  3. GNU C扩展中的sizeof(void)特性

2.1、宏的整体构成

宏的主体如下:

(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

乍一看可能较为复杂,下面逐步解析其工作原理。

2.2、解析整体常量表达式部分

首先,分析 ((void *)((long)(x) * 0l)) 这一部分。这里将 (long)(x) 进行类型转换,主要是为了允许 x 具有指针类型,同时避免在32位平台上的u64类型出现警告。

根据 C 标准 6.6.6,如果 x 是一个整型常量表达式,那么 ((long)(x) * 0l) 就是一个值为0的整型常量表达式。而根据 C 标准 6.3.2.3.3,值为0的整型常量表达式或者将其转换为 void* 类型的表达式被称为空指针常量。因此,此时 (void *)((long)(x) * 0l) 就是一个空指针常量。

如果 x 不是整型常量表达式,不管 (void *)((long)(x) * 0l) 的值是多少,它都不是空指针常量。

2.3、条件运算符的作用

接着,分析 8? ((void *)((long)(x) * 0l) : (int *)8 这部分。这里使用8作为条件判断的一部分,其中第二个8是为了避免编译器在创建指向未对齐地址的指针时发出警告,第一个8可以是1。

C 标准 6.5.15-6规定条件运算符的特性,当其中一个操作数是空指针常量时,结果将具有另一个操作数的类型;否则,如果一个操作数是指向 void 的指针或 void 的限定版本,结果类型会是指向 void 的适当限定版本的指针。

因此,如果 x 是一个整型常量表达式,那么 ((void *)((long)(x) * 0l) 是一个空指针常量,此时整个条件表达式的结果就是第三个操作数 (int *)8 的类型,即指向 int 的指针。反之,如果 x 不是整型常量表达式,结果就是指向 void 的指针。

2.4、最终的判断依据

根据上述情况,有两种可能的情况:

sizeof(int) == sizeof(*((int *) (NULL)))    // (x)是常量表达式
sizeof(int) == sizeof(*((void *)(....)))    // (x)不是常量表达式
// 最终结果为:
sizeof(int) == sizeof(int)                  // (x)是常量表达式
sizeof(int) != sizeof(void)                 // (x)不是常量表达式

根据 GNU C 扩展,sizeof(void) == 1。因此,如果 x 是整数常量表达式,宏的结果为1;否则为0。由于比较的是两个 sizeof 表达式,最终结果本身也是一个整数常量表达式。

需要注意的是,常量表达式不能包含赋值、增量、减量、函数调用或逗号运算符,除非它们在未计算的子表达式中。同时,整型常量表达式只能包含整型常量、枚举常量、字符常量、结果为整型常量的 sizeof 表达式以及作为强制转换直接操作数的浮点常量,并且整型常量表达式中的强制转换运算符只能将算术类型转换为整型,作为 sizeof 运算符操作数的一部分除外。

简而言之,如果输入的参数是整型常量表达式,__is_constexpr(x) 宏会返回值为1的整型常量表达式;否则,返回值为0的整型常量表达式。

3、引入该宏的原因

3.1、与变量长度数组(VLAs)的关系

该宏的引入与从 Linux 内核中删除所有变量长度数组(Variable Length Arrays,简称 VLAs)的工作密切相关。为了实现这一目标,开发人员需要启用 GCC 的 -Wvla 警告,以标记出所有的 VLAs 实例。

当 -Wvla 警告被激活后,GCC 会报告许多数组被判定为 VLAs 的情况。例如在 fs/btrfs/tree-checker.c 中:

#define BTRFS_NAME_LEN 255
#define XATTR_NAME_MAX 255char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];

开发人员期望 max(BTRFS_NAME_LEN, XATTR_NAME_MAX) 被解析为255,即希望它被视为标准数组(非 VLA),但这取决于 max(x, y) 宏的扩展结果。

如果数组的大小不是 C 标准定义的(整数)常量表达式,GCC 会生成 VLA 代码。例如:

#define not_really_constexpr ((void)0, 100)int a[not_really_constexpr];

根据 C90 标准,因为使用了逗号运算符,((void)0, 100) 不是常量表达式。此时,GCC 会生成 VLA 代码,即便它知道这个大小是一个编译时的常量。

由于内核中的 max(x, y) 宏不是常量表达式,GCC 会触发警告并生成开发人员不希望的 VLA 代码。因此,一些内核开发人员尝试寻找 max 宏和其他宏的替代版本,以避免出现警告和 VLA 代码。有些开发人员尝试利用 GCC 的 __builtin_constant_p 内置函数,但未能完美适用于当时内核支持的所有 GCC 版本(GCC >= 4.4)。

后来,Martin Uecker 提出了一种聪明的方法:

#define ICE_P(x) (sizeof(int) == sizeof(*(1? ((void*)((x) * 0l)) : (int*)1)))

该方法虽然使用了 GCC 扩展,但备受好评,成为 __is_constexpr(x) 宏的关键思路。经过几次迭代,最终 __is_constexpr(x) 宏出现在内核中。该宏用于实现 max 宏和其他宏,使其必须是常量表达式,从而避免 GCC 生成 VLA 代码。

4、实验验证

为了更好地理解 __is_constexpr(x) 宏,可以进行以下实验:

#define multiply_zero(x) ((long)(x) * 0l)
int main(void)
{const int a = 2;int arr1[multiply_zero(a)];int arr2[multiply_zero(2)];return 0;
}

打开编译器的 -Wvla 选项时,如果 x 输入的是变量 a,在编译时期,multiply_zero(a) 无法计算,因此不是常量表达式。而 multiply_zero(2) 则是常量表达式。

$ gcc -Wvla test_vla.c
test_vla.c: In function ‘main’:
test_vla.c:5:2: warning: ISO C90 forbids array ‘arr1’ whose size can’t be evaluated [-Wvla]5 |  int arr1[multiply_zero(a)];|  ^~~

5、参考资料

Linux内核中max()宏的奥妙何在?(一)

Linux内核中max()宏的奥妙何在?(二)——大神Linus对这个宏怎么看?

http://www.dtcms.com/wzjs/171517.html

相关文章:

  • 网站欣赏百度推广的效果
  • 什么是网站外链360站长平台链接提交
  • 北京网站制作公司招聘关键词网站推广
  • 贵阳市做网站公司百度seo关键词排名查询
  • 网站区域名怎么注册公司产品推广文案
  • 电脑网站与手机的区别是什么网站搜索引擎推广
  • 做网站需要多少屏seo教学培训
  • 小型教育网站的开发建设开题报告收录批量查询工具
  • 国外好的做电视包装的网站亚马逊免费的关键词工具
  • 企业网站制作 南京百度推广的优化软件
  • axcure做网站ui网络营销策划的目的
  • 站长工具 怎么做网站地图百度手机助手下载正版
  • 深圳免费建站百度公司高管排名
  • 免费做ppt网站怎么优化推广自己的网站
  • 成都网站制作电话广告宣传方式有哪些
  • 做网站后台学什么专业外链服务
  • 恩施哪里有做网站的护肤品推广软文
  • 图书类网站开发的背景百度竞价登录入口
  • 网站建设的三网合一百度竞价排名机制
  • 我们不仅仅做网站更懂得网络营销郑州做网站最好的公司
  • 深圳建站服务公司有哪些搜索引擎网站
  • 2022腾讯云网站建设方案书寻找客户的渠道和方法
  • 国内移动端网站做的最好的seo优化网站技术排名百度推广
  • 海外医疗网站建设深圳网站推广公司
  • 百度推广要不要建网站深圳seo优化公司
  • 攸县网站制作公司信息流优化师面试常见问题
  • 用html5制作个人网站网络营销成功的品牌
  • 网站的静态资源服务器怎么做seo排名赚app靠谱吗
  • 为企业做优做强厦门seo外包
  • dw管理动态网站模板下载谷歌海外广告投放推广