GCC自带的一些builtin内建函数

2023-05-16

title: GCC自带的一些builtin内建函数
date: 2021-02-27 18:57:00
description: 一些GCC自带的内建(bulitin)函数的接口及实现


一、GCC内建函数
 最近在刷 leetcode 的时候遇到了一些以__builtin开头的函数,它们被用在状态压缩相关的题目中特别有用,于是就去了解了一下。

 原来这些函数是GCC编译器自带的内建函数。这些__builtin_*形式的内建函数一般是基于不同硬件平台采用专门的硬件指令实现的,因此性能较高。在刷题时可以直接用而不用重复造轮子,尤其是一些涉及到位操作的内建函数真的特别有用。

 我对其中涉及到位运算的内建函数挺感兴趣的,于是就去查了一下它们的接口以及具体实现。下一节主要介绍一下几个特别有用的函数。

 关于GCC内建函数的更完整的内容可以参见 官方文档。

二、常用的内建函数及实现
 针对实现,只实现64位无符号整型的版本。其余的版本依此类推。

1、__builtin_ctz
 一共有三个函数,分别适用于不同的输入类型。   

 int __builtin_ctz (unsigned int x)
 Returns the number of trailing 0-bits in x, starting at the least significant bit 
  position. If x is 0, the result is undefined.

  int __builtin_ctzl (unsigned long)
  Similar to __builtin_ctz, except the argument type is unsigned long.

  int __builtin_ctzll (unsigned long long)
  Similar to __builtin_ctz, except the argument type is unsigned long long.


 这个函数作用是返回输入数二进制表示从最低位开始(右起)的连续的0的个数;如果传入0则行为未定义。三个函数分别用于unsigned int,unsigned long以及unsigned long long。

实现
   

int __builtin_ctzl(unsigned long x) {
        for (int i = 0; i != 64; ++i)
            if (x >> i & 1) return i;
        return 0;
    }

 


    int __builtin_ctzl(unsigned long x) {
        int r = 63;
        x &= ~x + 1;
        if (x & 0x00000000FFFFFFFF) r -= 32;
        if (x & 0x0000FFFF0000FFFF) r -= 16;
        if (x & 0x00FF00FF00FF00FF) r -= 8;
        if (x & 0x0F0F0F0F0F0F0F0F) r -= 4;
        if (x & 0x3333333333333333) r -= 2;
        if (x & 0x5555555555555555) r -= 1;
        return r;
    }


2、__builtin_clz
 一共有三个函数,分别适用于不同的输入类型。   

 int __builtin_clz (unsigned int x)
    Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.

    int __builtin_clzl (unsigned long)
    Similar to __builtin_clz, except the argument type is unsigned long.

    int __builtin_clzll (unsigned long long)
    Similar to __builtin_clz, except the argument type is unsigned long long.


 这个函数作用是返回输入数二进制表示从最高位开始(左起)的连续的0的个数;如果传入0则行为未定义。三个不同的函数分别用于unsigned int,unsigned long以及unsigned long long。

实现
 

  int __builtin_clzl(unsigned long x) {
        for (int i = 0; i != 64; ++i)
            if (x >> 63 - i & 1) 
                return i;
    }

 

  int __builtin_clzl(unsigned long x) {
        int r = 0;
        if (!(x & 0xFFFFFFFF00000000)) r += 32, x <<= 32;
        if (!(x & 0xFFFF000000000000)) r += 16, x <<= 16;
        if (!(x & 0xFF00000000000000)) r += 8,  x <<= 8;
        if (!(x & 0xF000000000000000)) r += 4,  x <<= 4;
        if (!(x & 0xC000000000000000)) r += 2,  x <<= 2;
        if (!(x & 0x8000000000000000)) r += 1,  x <<= 1;
        return r;
    }


3、__builtin_ffs
 一共有三个函数,分别适用于不同的输入类型。   

 int __builtin_ffs (unsigned int x)
    Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.

    int __builtin_ffsl (unsigned long)
    Similar to __builtin_ffs, except the argument type is unsigned long.

    int __builtin_ffsll (unsigned long long)
    Similar to __builtin_ffs, except the argument type is unsigned long long.


 这个函数作用是返回输入数二进制表示的最低非0位的下标,下标从1开始计数;如果传入0则返回0。三个不同的函数分别用于unsigned int,unsigned long以及unsigned long long。

实现
 除输入0以外,满足 __builtin_ffs(x) = __builtin_ctz(x) + 1 。

  int __builtin_clzl(unsigned long x) {
        if (x == 0) return 0;
        return __builtin_ctz(x) + 1;
    }


4、__bulitin_popcount
 一共有三个函数,分别适用于不同的输入类型。

    int __builtin_popcount (unsigned int x)
    Returns the number of 1-bits in x.

    int __builtin_popcountl (unsigned long)
    Similar to __builtin_popcount, except the argument type is unsigned long.

    int __builtin_popcountll (unsigned long long)
    Similar to __builtin_popcount, except the argument type is unsigned long long.



 这个函数作用是返回输入的二进制表示中1的个数;如果传入0则返回 0 。三个不同的函数分别用于unsigned int,unsigned long以及unsigned long long。

实现

    int __builtin_popcountl(unsigned long x) {
        int r = 0;
        do{
            r += x & 1;
        while (x >>= 1);
        return r;
    }

 

    int __builtin_popcountl(unsigned long x) {
        int r = 0;
        for (; x; x &= x - 1) ++r;
        return r;
    }

 

    int __builtin_popcountl(unsigned long x) {
        x = (x & 0x5555555555555555) + (x >> 1  & 0x5555555555555555);
        x = (x & 0x3333333333333333) + (x >> 2  & 0x3333333333333333);
        x = (x & 0x0F0F0F0F0F0F0F0F) + (x >> 4  & 0x0F0F0F0F0F0F0F0F);
        x = (x & 0x00FF00FF00FF00FF) + (x >> 8  & 0x00FF00FF00FF00FF);
        x = (x & 0x0000FFFF0000FFFF) + (x >> 16 & 0x0000FFFF0000FFFF);
        x = (x & 0x00000000FFFFFFFF) + (x >> 32 & 0x00000000FFFFFFFF);
        return x;
    }

 

    int __builtin_popcountl(unsigned long x) {
        x -= (x >> 1) & 0x5555555555555555;
        x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
        x = x + (x >> 4) & 0x0F0F0F0F0F0F0F0F;
        return x * 0x0101010101010101 >> 56;
    }


5、__bulitin_popcount
 一共有三个函数,分别适用于不同的输入类型。

    int __builtin_parity (unsigned int x)
    Returns the parity of x, i.e. the number of 1-bits in x modulo 2.

    int __builtin_parityl (unsigned long)
    Similar to __builtin_parity, except the argument type is unsigned long.

    int __builtin_parityll (unsigned long long)



 这个函数作用是返回输入的二进制表示中1的个数的奇偶,也就是输入的二进制中1的个数对2取模的结果。三个不同的函数分别用于unsigned int,unsigned long以及unsigned long long。

实现
 根据定义,等价于__builtin_popcount(x) & 1 。

    int __builtin_parityl(unsigned long x) {
        return __builtin_popcountl(x) & 1;
    }

 

    int __builtin_parityl(unsigned long x) {
        x ^= x >> 1;
        x ^= x >> 2;
        x ^= x >> 4;
        x ^= x >> 8;
        x ^= x >> 16;
        x ^= x >> 32;
        return x & 1;
    }


 这几个函数中都有很巧妙的位运算,大大降低了复杂度。关于位运算的更多例子,可以参考链接 [4] 。

[1]https://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Other-Builtins.html#Other-Builtins
[2]https://www.cnblogs.com/justinh/p/7754655.html
[3]https://xr1s.me/2018/08/23/gcc-builtin-implementation/
[4]http://graphics.stanford.edu/~seander/bithacks.html
————————————————
版权声明:本文为CSDN博主「Shy_tom」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38877888/article/details/114190682

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC自带的一些builtin内建函数 的相关文章

  • 开源自制6通道航模遥控器,Arduino Pro Mini NRF24L01模块

    前言 前段时间跟着LOLI大神的教程制作了LOLI三代控 xff0c 效果很好 但是 xff0c 由于LOLI三代控的接收机带有数据回传功能 xff0c 也就是接收机的无线模块也承担了发射数据功能 xff0c 所以接收机也要使用带有功率放大
  • linux下TCP/IP通讯实例

    下面是server端源码 xff1a include lt stdio h gt include lt stdlib h gt include lt string h gt include lt unistd h gt include lt
  • STM32 USART 一些问题

    SECTION 1 1 2 3 4 5 6 7 8 9 10 11 12 13
  • 数据缓冲策略 —— 无缓冲、行缓冲、全缓冲(缓冲区大小测试)

    printf打印数据时 xff0c 一般会先把数据放入C缓冲区 xff0c 然后再刷新到内核缓冲区 xff0c 最后再写入硬件 这个过程中 xff0c 数据从C缓冲区迁移到内核缓冲区的操作我们称为缓冲 xff08 也可以理解为刷新 xff0
  • K210 FreeRTOS多任务多核系统调度

    一 目的 众所周知 xff0c K210这款AI新品是一款64bit 双核芯片 xff0c 其支持裸机编程 xff0c 并且官方也提供freertos sdk xff0c 方便开发者在其上进行多任务应用开发 那么如何进行任务创建和多核开发呢
  • keil如何添加h文件_KEIL 那些编辑技巧与方法

    当然了 xff0c 很多人现在更多的是使用 VSCode 或者 SI 等软件进行编辑 xff0c 但不可否认的是 xff0c 还有很多道友还是选择 KEIL 作为编辑软件的 xff0c 本篇笔记作为一个编辑技巧的总结 关于 KEIL 软件的
  • 关于keil C51 案例 加入头文件

    1 先在工程下面建立一个 h文件 xff0c 例如delay h 在其中写入要加入的函数声明 xff0c 或者其他的一些预定义 xff1a ifndef DELAY H define DELAY H include lt reg52 h g
  • "extern C", 你真的懂了吗?

    在c 43 43 prime书中看到过 xff0c 在DLL和lib中看到过 xff0c 但是每次看过就不求甚解地一扫而过 心里知道有extern c这个语句 xff0c 却不知道该用在哪里 xff0c 又能起到什么作用 唉 xff0c 想
  • 内存或寄存器定义和赋值

    在嵌入式中 xff0c 会经常遇到寄存器 内存的数据传输 xff0c 如何向寄存器中写入数据呢 xff1f 现举例说明 xff1a define rDISRC0 volatile unsigned 0x4b000000 DMA 0 Init
  • Makefile的文件格式,详解规则

    构建规则都写在Makefile文件里面 xff0c 要学会如何Make命令 xff0c 就必须学会如何编写Makefile文件 1 概述 Makefile文件由一系列规则 xff08 rules xff09 构成 每条规则的形式如下 xff
  • 只声明而不定义变量

    如果想声明一个变量而不定义它 xff0c 就在变量前面添加关键字extern xff0c 而且不要显式地初始化变量 extern int i 声明i而非定义i extern int j 61 0 定义 int k 声明并且定义 注意 xff
  • vector 与 智能指针使用注意事项

    看以下代码 xff0c 执行时会有什么问题 xff1f include lt vector gt include lt stdio h gt include lt stdlib h gt include lt memory gt class
  • SystemV 共享内存(一)—— 共享内存的创建与释放(shmget / shmctl)

    匿名管道和命名管道都是基于文件 的进程间通信 xff0c SystemV方案是在OS内核层面 专门为进程间通信设计的一个方案 xff0c 然后通过系统调用 xff08 system call xff09 给用户提供通信接口 SystemV方
  • TTL 485 232 全双工 半双工 单工---精简总结

    全双工 xff1a 双向2车道 半双工 xff1a 双向1车道 单工 xff1a 单向车道 1 从单片机软件编程角度来说 xff0c RS232 RS485都是转换为TTL电平方式与单片机通信 xff08 CAN收发器把差分信号转化为TTL
  • STM32F4-ADC-常规通道-转换模式配置-总结

    STM32F4 ADC常规通道转换的模式配置 模式选择 此寄存器定义 xff1a 是否自动循环 这两个寄存器定义 xff1a Scan mode xff08 是否轮询序列 xff09 和Discontinuous mode xff08 是否
  • 单片机 裸机 架构

    以前是 while xff08 1 xff09 43 软件定时器 43 中断标志 的框架 xff0c 现在的项目我想尝试一下新的框架 xff0c 简单来说是 主状态机 43 大量子状态机 43 软件定时器 的方式 xff0c 这其中状态机和
  • USART---串口发送数据

    xfeff xfeff while USART1 gt SR amp 0X40 61 61 0 等待发送结束 解析 xff1a USART1 gt SR xff1a 串口 状态 寄存器 USART1 gt SR amp 0X40 即串口状态
  • STM32---串口初始化

    u8 USART RX BUF USART REC LEN 接收缓冲 最大USART REC LEN个字节 bit15 xff0c 接收完成标志 bit14 xff0c 接收到0x0d bit13 0 xff0c 接收到的有效字节数目 u1
  • stm32---RS485初始化

    u8 RS485 RX BUF 64 接收缓冲 最大64个字节 u8 RS485 RX CNT 61 0 接收到的数据长度 函数 xff1a RS485 Init 功能 xff1a 串口初始化配置 参数 xff1a Baud 波特率 备注
  • 定时器0,中断,控制LED闪烁(1s亮,1s灭)---2018-11-07

    include lt reg52 h gt include lt stdio h gt define uchar unsigned char define uint unsigned int sbit LED 61 P2 2 void ti

随机推荐

  • AM2322温湿度传感器(地址0XB8)---I2C总结(I2C_ModBus协议)

  • 数码管---共阳---共阴---段选码---位选码---总结

    共阴极 xff1a 位选为低电平 xff08 即0 xff09 选中数码管 各段选为高电平 xff08 即1接 43 5V时 xff09 选中各数码段 0 f 共阴数码管段选 表 xff0c 无小数点 xff1a unsigned char
  • ubuntu怎样通过终端打开firefox?

    1 直接输入firefox 按回车 2 首先打开火狐浏览器 xff0c 鼠标移到屏幕最顶端 xff0c 出现菜单栏 工具栏 xff0d xff0d 附加组件选项 如下图所示 也可以在火狐浏览器界面 使用快捷键 shift 43 Ctrl 4
  • 重新认识 IP地址

    目录 一 什么是网段划分 二 如何分配子网中的IP xff1f 三 IP地址的分类 1 早期划分方式 1 早期分类方式 2 早期分类的局限性 2 CIDR划分 xff08 子网掩码划分 xff09 1 基本思路 2 实现方式 四 IP地址的
  • Linux服务器下抓包工具tcpdump分析

    概述 说到抓包分析 xff0c 最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了 xff0c 但是有时候由于接口调用无法在客户端抓包 xff0c 只能在服务器上抓包 xff0c 这种情况下怎么办呢 xff1f 本
  • MATLAB 常用转义字符

    MATLAB常用转义字符收录如下 Single quotation mark nbsp Percent character nbsp Backslash nbsp a Alarm nbsp b Backspace nbsp f Form f
  • 利用MATLAB解决人工神经网络模拟预测问题研究

    利用MATLAB解决人工神经网络模拟预测问题研究 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 人工神经网络根据模仿人脑的工作原理抽象出来的一种算法 人工神经网络 artigicial neutral ne
  • Visual Studio 2008学习过程(之一)起步

    以前 xff0c 在使用MATLAB开发一些软件 xff0c 虽然它的数值计算方面的功能很强大 xff0c 但是界面不是很好看 xff0c 很难做出来漂亮的软件 xff0c 所以萌生了用VS和MATLAB联合编程的想法 这样可以使软件更加强
  • 如何用servlet写网页访问量计数器?

    如何用servlet写网页访问量计数器 xff1f 1 原料 l MyEclipse l Tomcat l html 2 步骤 1 新建工程 项目栏鼠标右键 New Web Project xff0c 这里我起名为 xff1a myexm4
  • 提示:请安装TCP/IP协议.error=10106。解决方案

    有朋友使用电脑的时候会出现如下错误 xff0c 如何解决该问题是本文写作的目的 提示错误 xff1a 图 1 解决 方案 xff1a 1 删除两个注册表选项 xff1b 按下windows键 43 R键 xff0c 输入regedit xf
  • 防止头文件被重复包含

    前言 为了避免同一个文件被include多次 xff0c C C 43 43 中有两种方式 xff0c 一种是 ifndef方式 xff0c 一种是 pragma once方式 方式一 xff1a ifndef SOMEFILE H 或写为
  • 有趣的网站分享——pornhub风格生成器

    寄语 要说logo设计 xff0c pornhub的logo设计让人印象深刻 xff0c 黑底白字 xff0c 配上一小撮橙色 xff0c 给人极强的冲击力 这不 xff0c 有一个有意思的程序员弄了一个网站 xff0c 专门生成pornh
  • 大小端存储问题

    1 什么是数据的高低位 数据的高位在左 xff0c 低位在右 2 什么是内存的高低位 2 什么是大端存储 小端存储 简单记就是 xff1a 小端 xff1a 低低 xff08 数据低位在内存低位 xff09 大端 xff1a 高低 xff0
  • 【A星算法的优化方案】

    当地图很大的时候 xff0c 或者使用A星算法的寻路频率很高的时候 xff0c 普通的A星算法就会消耗大量的CPU性能急剧下降 xff0c 普通的A星性能还是不过关 接下来我们讲讲A星寻路在遇到性能瓶颈时的优化方案 一 长距离导航 当距离很
  • Java工具类:String与DateTime类型的相互转换

    1 String 转 DateTime 在转换之前需要引入 hutool 依赖 String datestr 61 34 2022 5 19 34 DateTime datetime 61 DateUtil parse datestr 2
  • Iterator迭代器的一般用法

    Iterator迭代器的一般用法 迭代器 xff08 Iterator xff09 迭代器是一种设计模式 xff0c 它是一个对象 xff0c 它可以遍历并选择序列中的对象 xff0c 而开发人员不需要了解该序列的底层结构 迭代器通常被称为
  • socket编程---fgets和fputs函数使用理解

    这一节是继续上一节socket05的讨论 xff0c 来探讨在使用socket进行通信中遇到的一些函数使用理解误区 1 fgets的使用注意点 在写socket通信 xff08 代码见上一篇中 xff0c 只是将sendbuf和recvbu
  • Tarjan算法详细讲解

    Tarjan算法讲解的博客网上找到三篇比较好的 现在都转载了 个人只研究了第一篇 正如博主所说 讲的标比较详细 清晰 剩下两篇也可以看一下 卿学姐视频讲解 https www bilibili com video av7330663 以下内
  • 中文乱码在线恢复网站

    乱码恢复
  • GCC自带的一些builtin内建函数

    title GCC自带的一些builtin内建函数 date 2021 02 27 18 57 00 description 一些GCC自带的内建 bulitin 函数的接口及实现 一 GCC内建函数 最近在刷 leetcode 的时候遇到