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編碼字符。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM