Apple LLVM4.2对C11标准的支持
今天下了Apple最新的XCode4.6,里面包含了最新的Apple LLVM4.2编译器,其中令人十分欣喜的是C语言编译器语言选项中多了C11以及gnu11。
之前在Apple LLVM4.0开始就已经支持了C11标准中一个比较重要的语法特性——泛型机制(详细可参考这篇博文:
C11标准的泛型机制
)。而现在,既然已经彻底推出了GNU11规范,那么我们来简单地探究一下,此次Apple LLVM4.2支持了哪些C11标准中的语法特性。
我这里列出了5大语法特性:
1、数据对齐(Alignment)
2、泛型表达式(Type-generic expressions)
3、原子数据类型(Atomics)
4、静态断言:(static assertion)
5、匿名结构与联合(Anonymous structures and unions)——其实这个语法特性在GNU扩展语法中已经被GCC编译器所支持。
下面提供一些样例代码来介绍这些特性以及如何使用这些特性:
// // main.c // CTest // // Created by zenny_chen on 12-12-1. // Copyright (c) 2012年 zenny_chen. All rights reserved. // #include <stdio.h> #include <stdalign.h> #include <stddef.h> // no max_align_t #include <string.h> //#include <threads.h> not defined //#include <uchar.h> not defined //#include <stdatomic.h> not defined #define Zenny_IsEqual4BasicTypes(a, b) _Generic((a), \ const char*: strcmp(a, b) == 0, \ char*: strcmp(a, b) == 0, \ const char[sizeof(a)]: strcmp(a, b) == 0, \ char[sizeof(a)]: strcmp(a, b) == 0, \ default: (a) == (b)) static volatile _Atomic(int) a = 100; int main(int argc, const char * argv[]) { // 1. Alignment char _Alignas(long double) buf1[30] = { [0] = 10, [2] = -128, [29] = 127 }; char _Alignas(32) buf2[7] = { [0] = 10, [2] = -128 }; printf("The address of buf1 is: 0x%.16lX\n", (size_t)buf1); // 16-byte aligned printf("The address of buf1 is: 0x%.16lX\n", (size_t)buf2); // 32-byte aligned // 在C++的<cstddef>中定义了max_align_t为long double,但在C的<stddef.h>头文件中没有定义 printf("The max align size is: %lu\n", _Alignof(long double)); // 2. Type-generic expressions printf("1 == 2? %d\n", Zenny_IsEqual4BasicTypes(1, 2)); const char words[] = "Hi"; printf("Hi == words? %d\n", Zenny_IsEqual4BasicTypes("Hi", words)); // Use char[3] printf("words == Hi? %d\n", Zenny_IsEqual4BasicTypes(words, "Hi")); // Use const char[3] // 3. Atomics _Atomic(int) volatile *p = &a; ++(*p); printf("The value is: %d\n", a); // 4. _Static_assert: _Static_assert会在编译时做断言处理,因此第一个参数必须是常量表达式 _Static_assert(sizeof(void) == 1, "sizeof(void) !=1 and that is not expected!"); // 5. Anonymous structures and unions struct T { int tag; union { int i; float f; }; }; struct T t = {.tag = 100, .f = -100.25f}; printf("The improper value is: %d\n", t.tag + t.i); printf("The suitable value is: %f\n", t.tag + t.f); return 0; }
在Apple LLVM4.2中没被实现的C11标准有:
1、与<threads.h>相关的特性,包括不支持_Thread_local关键字。
2、与<uchar.h>相关的特性,包括不支持char16_t以及char32_t。
3、不支持_Noreturn函数指示符。
我同时也在Ubuntu下用了GCC4.7.2。该编译器支持了<uchar.h>以及_Noreturn,但是对_Generic尚未支持。
而在最新的LLVM Clang中看到了Clang C编译器又增加了一个非常有趣的特性——函数重载。这个重载方式与限制跟C++中的一样。只需通过__attribute__((overloadable))来指定即可。下面看一下示例代码:
static void __attribute__((overloadable)) MyFunc(float x) { puts("This is a float function"); } static int __attribute__((overloadable)) MyFunc(int x) { puts("This is an integer function"); return x; } int main(void) { MyFunc(1.0f); MyFunc(1); }
关于LLVM Clang更多信息可以参考此链接:http://clang.llvm.org/docs/index.html
这里会放最新LLVM Clang版本的手册以及各类文档。
而到了Apple LLVM 5.0之后,对C11标准的UTF-8、UTF-16以及UTF32编码格式都有了非常好的支持提升。C11标准中,字符串前缀u8表示以UTF-8编码的字符串,u前缀表示UTF-16编码的字符串,U前缀表示UTF-32编码的字符串。其中,UTF-8编码是变长编码格式,一个字符所占字节数从1到6字节不等。而UTF-16是定长编码,一个字符总是2个字节。UTF-32也是定长编码,一个字符总是4个字节。比如以下代码:
const char *utf8Str = u8"哈罗"; unichar utf16c = u'你'; unsigned utf32c = U'好'; const unichar *utf16Str = u",世界!"; printf("UTF-16 char size is: %lu\n", sizeof(u'你')); // 2个字节 printf("UTF-32 char size is: %lu\n", sizeof(U'好')); // 4个字节 NSString *str = [NSString stringWithCString:utf8Str encoding:NSUTF8StringEncoding]; NSLog(@"str = %@", str); str = [NSString stringWithFormat:@"%C%C%S", utf16c, (unichar)utf32c, utf16Str]; NSLog(@"str = %@", str);
这里需要注意,u8前缀只能跟字符串字面量,而不能跟字符字面量。而u以及U既可以跟字符字面量也可以跟字符串字面量。
不过,在Apple LLVM5.0以及Apple LLVM 5.1中,尚未引入<uchar.h>标准库。但是它已经定义了unichar这个类型,它实际上是unsigned short类型,正好能对上UTF-16字符。而对于UTF-32编码,由于不管是iOS还是OS X都没有开始很好支持,因此仅仅是语法上支持而已。这里用unsigned来存UTF-32编码字符。