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编码字符。

posted @ 2013-01-30 14:13  zenny_chen  Views(2493)  Comments(3Edit  收藏  举报