Hexagon LLVM编译架构介绍(19)

LLVM编译器在C语言兼容性方面支持多种标准模式,如C89、C99,并尝试与GCC保持兼容,但不支持某些GCC扩展。未实现的GCC扩展包括#pragma weak、十进制浮点型等;有意不支持的扩展有结构体中的可变长度数组等。对于Microsoft扩展,LLVM提供部分支持,如-fms-extensions,但支持并不完整。此外,LLVM对左值转换和内联汇编有特定的处理方式。
摘要由CSDN通过智能技术生成

6 语言兼容性

LLVM 努力既符合当前的语言标准(C99、C++98),也实现了许多在其他编译器中可用的广泛使用的扩展,以便在使用 LLVM 编译器时,大多数正确的代码将“正常工作”。 但是,LLVM 比其他流行的编译器更严格,并且可能会拒绝其他编译器允许的错误代码。

本章介绍 LLVM 的常见兼容性和可移植性问题,以帮助您在 LLVM 发出错误消息时理解和修复代码中的问题。

它涵盖以下主题:

  • C兼容性
  • C++兼容性

6.1 C兼容性

6.1.1 各种标准模式的区别

LLVM 支持 -std 选项,该选项会更改 LLVM 使用的语言模式。 C 支持的模式是 c89、gnu89、c94、c99、gnu99 以及这些模式的各种别名。 如果未指定 -std 选项,则 LLVM 默认为 gnu99 模式。

c* 和 gnu* 模式有以下区别:

  • c* 模式定义__STRICT_ANSI__。
  • 在gnu* 模式中特定于目标的定义不以下划线为前缀(例如“linux”)。
  • 在gnu* 模式下,Trigraphs 默认关闭; 它们可以通过 -trigraphs 选项启用。
  • 解析器将asm 和typeof 识别为gnu* 模式下的关键字; asmtypeof 变体在所有模式下都可以识别。
  • 根据标准是 VLA 的数组,但可以由编译器前端常量折叠的数组被视为固定大小的数组。 这发生在诸如“int X[(1, 2)];”之类的事情上,这在技术上是一个 VLA。 c* 模式严格遵守并将它们视为 VLA。

*89 和 *99 模式有以下区别:

  • 99 模式默认实现 C99 中指定的内联,而 *89 模式实现 GNU 版本。 对于具有 gnu_inline 属性的单个函数,这可以被覆盖。
  • 在c89 模式下无法识别有向图。
  • 在for、if、switch、while 或do 语句中定义的名称范围是不同的。(例如:“if ((struct x {int x;}*)0) {}”。)
  • STDC_VERSION 在*89 模式中未定义。
  • inline 在c89 模式下不被识别为关键字。
  • restrict 在*89 模式中不被识别为关键字。
  • *99 模式下的整数常量表达式中允许使用逗号。
  • 在*89 模式下,不是左值的数组不会被隐式提升为指针。
  • 有些警告是不同的。

c94 模式与 c89 模式相同,只是在 c94 模式下启用了有向图。

6.1.2 尚未实现 GCC 扩展

LLVM 尝试尽可能地与 GCC 兼容,但以下 GCC 扩展尚未在 LLVM 中实现:

  • #pragma weak – 这可能会在未来的某个时候实施,至少是部分实施。
  • 十进制浮点型(_Decimal32 等)和定点型(_Fract 等)- 目前还没有人表示对这些感兴趣,因此目前尚不清楚何时实施。
  • 嵌套函数——这是一个很少使用的复杂功能,因此不太可能很快实现。
  • 全局寄存器变量——这不太可能很快实现,因为它需要额外的 LLVM 后端支持。
  • 灵活数组成员的静态初始化——这似乎是一个很少使用的扩展,但可以根据用户需求实施。
  • __builtin_va_arg_pack 和__builtin_va_arg_pack_len – 这很少使用,但在一些可能有趣的地方,例如glibc 头文件,所以它可能会根据用户需求实现。 请注意,由于 LLVM 伪装成 GCC 4.2,并且此扩展是在 4.3 中引入的,因此 glibc 标头当前不会尝试将此扩展与 LLVM 一起使用。
  • 前向声明函数参数——不过,这还没有出现在任何现实世界的代码中,所以它可能永远不会被实现。

6.1.3 有意不支持的 GCC 扩展

LLVM 故意不实现以下 GCC 扩展:

  • 结构体中的可变长度数组——由于以下几个原因而没有实现这一点:实现起来很棘手,扩展完全没有记录,而且扩展似乎很少使用。 请注意,LLVM 确实支持灵活的数组成员(结构体末尾具有零或未指定大小的数组)。
  • 相当于GCC的“fold”——这意味着LLVM不接受GCC在需要常量表达式的上下文中可能接受的某些构造,例如“xx”,其中x是变量。
  • __builtin_apply 和相关属性——这个扩展极其晦涩难懂,难以可靠地实现。

6.1.4 Microsoft扩展

  • LLVM 有一些对 Microsoft Visual C++ 扩展的实验性支持; 要启用它,请使用选项 -fms-extensions 命令行。 这是 Windows 目标的默认设置。 请注意,该支持是不完整的:启用 Microsoft 扩展将悄悄删除某些构造(包括 __declspec 和 Microsoft 样式的 asm 语句)。

  • -fms-compatibility 使编译器接受足够多的无效 C++ 来解析大多数 Microsoft 标头。 默认情况下为 Windows 目标启用此标志。

  • -fdelayed-template-parsing 让LLVM 延迟所有模板实例化,直到翻译单元结束。 默认情况下为 Windows 目标启用此标志。

  • LLVM 允许使用-fmsc-version=n 设置_MSC_VER。 此选项默认值为 1300,与 Visual C/C++ 2003 中的相同。支持任何值,选择的值会极大地影响 LLVM 可以编译的 Windows SDK 和 c++stdlib 头文件。 当 LLVM 支持这些标头所需的全套 MS 扩展时,将删除此选项。

  • LLVM 不支持可以使用用户定义的 typedef 声明匿名记录成员的 Microsoft 扩展。

  • LLVM 支持用于控制记录布局的Microsoft pack pragma。 GCC 还包含对此功能的支持。 但是,在 MSVC 和 GCC 不兼容的情况下,LLVM 遵循 MSVC 定义。

  • LLVM 对于 Windows 目标默认为 C++11。

6.1.5 左值转换

旧版本的 GCC 允许将赋值的左侧转换为不同的类型。 LLVM 为这样的代码产生错误:

lvalue.c:2:3: error: assignment to cast is illegal, lvalue casts 
are not supported
(int*)addr = val;  
^~~~~~~~~~ ~

要解决此问题,请将转换移到右侧。 在这个例子中,可以使用:

addr = (float *)val;

6.1.6 内联汇编

一般来说,LLVM 与 GCC 内联汇编扩展高度兼容,允许使用与 GCC 内联汇编相同的一组约束、修饰符和操作数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值