GNU C内嵌汇编语言

  • GNU C语言提供了关键字asm来声明代码是内嵌的汇编语句

    • 如:

      1
      #define nop() __asm__ __volatile__ ("nop       \n\t")
  • C语言使用关键字__asm__和__volatile__对汇编语句进行修饰,这两个关键字在C语言内嵌汇编语句时经常使用

    • __asm__:用于声明这行代码是一个内嵌汇编表达式
    • __volatile__:其作用是告诉编译器此行代码不能被编译器优化
  • GNU C语言有着极其复杂的书写格式,将分为3个部分学习

    • 内嵌汇编表达式

    • 操作约束和修饰符

    • 序号占位符

内嵌汇编表达式

  • GNU C语言的内嵌汇编表达式由4部分构成,它们之间使用“:”号分割,其完整格式为
    • 指令部分 : 输出部分 : 输入部分 : 损坏部分
  • 如果将内嵌汇编表达式当作函数,指令部分是函数中的代码,输入部分用于向函数传入参数,输出部分可理解为函数的返回值。

4个部分的详细解释:

损坏部分的3种通知:

  • 寄存器修改通知
  • 内存修改通知
  • 标志寄存器修改通知

操作约束和修饰符

每个输入,可细分为:

  • 寄存器约束
  • 内存约束
  • 立即数约束

在输出表达式中,还有限定寄存器操作的修饰符

  • 详细解释:

  • 修饰符
    • &

序号占位符

  • 定义:是输入/输出操作约束的数值映射
  • 每个内嵌汇编表达式最多只有10条输入/输出约束,这些约束按照书写顺序依次被映射为序号0~9
  • 如果指令部分想引用序号占位符,必须使用百分号%前缀加以修饰
    • 如%0表示第一个操作约束
  • 为了区分序号占位符和寄存器,特别使用两个百分号(%%)来对寄存器加以修饰
  • 在%与序号占位符之间插入字母b表示操作最低字节,或插入字母h表示操作次低字节

GNU C语言对标准C语言的扩展

GNU C语言在标准C语言的基础上引入了诸多人性化的扩展

  • 柔性数组成员(或称零长数组、变长数组 )

    • GNU C语言允许使用长度为0的数组来增强结构体的灵活性,其在动态创建结构体时有着非常明显的优势
  • case关键字支持范围匹配

    • GNU C语言允许case关键字匹配一个数值范围,由此可以取代多级的if条件检测语句

      1
      2
      case 'a'...'z':
      break;
  • typeof关键字获取变量类型

    • 借助关键字typeof(x)可以取得变量x的数据类型
  • 可变参数宏

    • 在GNU C语言中宏函数允许使用可变参数类型

  • 元素编号

    • 标准C语言规定数组和结构体必须按照固定顺序对成员(或元素)进行初始化赋值
    • GNU C语言为使数组和结构体初始化更加自由,特意放宽该限制
      • 数组可以在初始化期间借助下标对某些元素进行赋值,并在结构体初始化过程中使用成员名直接对成员进行赋值
      • 允许数组和结构体按照任意顺序对成员(或元素)进行初始化赋值
  • 当前函数名

    • 为当前函数的名字准备了两个标识符
      • __PRETTY__FUNCTION__:保存着带有语言特色的名字
      • __FUNCTION__:保存着函数在源码中的名字
    • 在C函数中,这两个标识符代表的函数名字相同
  • 特殊属性声明

    • 允许使用特殊属性对函数、变量和类型加以修饰,以便对它们进行手工代码优化和定制
    • 在声明处加上关键字__attribute__((ATTRIBUTE))即可指定特殊属性
      • 关键字中的ATTRIBUTE是属性说明
      • 如有多个属性,必须用逗号隔开
    • 目前支持的属性说明有

    • noreturn属性用来修饰函数,表示该函数从不返回,会使编译器在优化代码时剔除不必要的警告信息
    • packed属性作用是取消结构在编译时的对齐优化,使其按照实际占用字节数对齐
    • regparm(n)属性用于以指定寄存器传递参数的个数,该属性只能用在函数定义和声明里
      • 寄存器参数的上限值为3(使用顺序为EAX、EDX、ECX),若超过3,剩余参数将使用内存传递方式
      • 该属性只在x86处理器体系结构下有效