Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

C 语言转换到仓颉胶水代码的规则

HLE 自动生成 C 语言到仓颉的胶水代码,支持函数、结构体、枚举和全局变量的翻译,类型支持:基础类型、结构体类型、指针、数组和字符串。

基础类型

工具支持以下几种基础类型:

C Typecangjie Type
voidunit
NULLCPointer
boolBool
charUInt8
signed charInt8
unsigned charUInt8
shortInt64
intInt32
unsigned intUInt32
longInt64
unsigned longUInt64
long longInt64
unsigned long longUInt64
floatFloat32
doubleFloat64
int arr[10]Varry

复杂类型

工具支持的复杂类型有:struct 类型、指针类型、枚举类型、字符串、数组。

struct 类型

.h 声明文件:

struct Point {
    struct {
        int x;
        int y;
    };
    int z;
};

struct Person {
    int age;
};

typedef struct {
    long long x;
    long long y;
    long long z;
} Point3D;

对应生成的胶水代码如下:

@C
public struct _cjbind_ty_1 {
    public let x: Int32
    public let y: Int32

    public init(x: Int32, y: Int32) {
        this.x = x
        this.y = y
    }
}

@C
public struct Point {
    public let __cjbind_anon_1: _cjbind_ty_1
    public let z: Int32

    public init(__cjbind_anon_1: _cjbind_ty_1, z: Int32) {
        this.__cjbind_anon_1 = __cjbind_anon_1
        this.z = z
    }
}

@C
public struct Person {
    public let age: Int32

    public init(age: Int32) {
        this.age = age
    }
}

@C
public struct Point3D {
    public let x: Int64
    public let y: Int64
    public let z: Int64

    public init(x: Int64, y: Int64, z: Int64) {
        this.x = x
        this.y = y
        this.z = z
    }
}

指针类型

.h 声明文件:

void* testPointer(int a);

对应生成的胶水代码如下:

foreign func testPointer(a: Int32): CPointer<Unit>

函数类型

.h 声明文件:

void test(int a);

对应生成的胶水代码如下:

foreign func test(a: Int32): Unit

枚举类型

.h 声明文件:

enum Color {
RED,
GREEN,
BLUE = 5,
YELLOW
};

对应生成的胶水代码如下:

public const Color_RED: Color = 0
public const Color_GREEN: Color = 1
public const Color_BLUE: Color = 5
public const Color_YELLOW: Color = 6

public type Color = UInt32

字符串

.h 声明文件:

void test(char* a);

对应生成的胶水代码如下:

foreign func test(a: CString): Unit

全局变量

目前只支持 C 语言中的基础类型的常量。

.h 声明文件:

const int GLOBAL_CONST = 42;

对应生成的胶水代码如下:

public const GLOBAL_CONST: Int32 = 42

数组类型

.h 声明文件:

void test(int arr[3]);

对应生成的胶水代码如下:

foreign func test(arr: VArray<Int32, $3>): Unit

不支持的规格

不支持的规格有:位域、联合体、宏、不透明类型、柔性数组、扩展类型。

位域

.h 声明文件:

struct X {
    unsigned int isPowerOn : 1;
    unsigned int hasError : 1;
    unsigned int mode : 2;
    unsigned int reserved : 4;
};

生成的对应的仓颉代码如下,需要用户手动修改正确:

@C
public struct X {
    let _cjbind_opaque_blob: UInt32

    public init() {
        this._cjbind_opaque_blob = unsafe { zeroValue<UInt32>() }
    }
}

联合体

.h 声明文件:

union X {
    int a;
    void* ptr;
};

生成的对应的仓颉代码如下,需要用户手动修改正确:

@C
public struct X {
    let _cjbind_opaque_blob: UInt64

    public init() {
        this._cjbind_opaque_blob = unsafe { zeroValue<UInt64>() }
    }
}

仓颉目前没有合适的表达式解析库,因此无法直接计算宏的值。在遇到宏时,当前会跳过整个 #define。

不透明类型

.h 声明文件:

typedef struct OpaqueType OpaqueType;

OpaqueType* create_opaque(int initial_value);
void set_value(OpaqueType* obj, int value);
int get_value(OpaqueType* obj);
void destroy_opaque(OpaqueType* obj);

生成的对应的仓颉代码如下,需要用户手动修改正确:

@C
public struct OpaqueType {
    init() {
        throw Exception("This type should be implemented by user")
    }
}

foreign func create_opaque(initial_value: Int32): CPointer<OpaqueType>

foreign func set_value(obj: CPointer<OpaqueType>, value: Int32): Unit

foreign func get_value(obj: CPointer<OpaqueType>): Int32

foreign func destroy_opaque(obj: CPointer<OpaqueType>): Unit

柔性数组

.h 声明文件:

typedef struct {
    int length;
    char data[];
} FlexibleString;

生成的对应的仓颉代码如下,需要用户手动修改正确:

@C
public struct FlexibleString {
    public let length: Int32
    public let data: CPointer<UInt8>

    public init(length: Int32, data: CPointer<UInt8>) {
        this.length = length
        this.data = data
    }
}

扩展类型

.h 声明文件:

#include <complex.h> // C 标准复数头文件
#include <stdatomic.h>

float _Complex c_float; // float 复数类型
double _Complex c_double; // double 复数类型
long double _Complex c_ld; // long double 复数类型

long double pi_high = 3.14159265358979323846264338327950288L; // 后缀 L 表示 long double 字面量
long double Planck_constant = 6.62607015e-34L; // 普朗克常数(高精度需求)

// 用 _Atomic 关键字声明原子类型(int 的原子封装)
_Atomic(int) counter = 0;

生成的对应的仓颉代码如下,需要用户手动修改正确:

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* float _Complex c_float */

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* double _Complex c_double */

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* long double _Complex c_ld */

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* long double pi_high = 3.14159265358979323846264338327950288L */

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* long double Planck_constant = 6.62607015e-34L */

/*FIXME: Non-constant global variable details need to be verified and rewritten by user.*/
/* _Atomic ( int ) counter = 0 */

说明:

  1. 内存对齐:仓颉没有提供对齐控制的语法,因此 HLE 工具使用 C 默认的对齐方式。如果 C 代码中使用了 #pragma pack 或者 __attribute__((packed)) 等方式来控制对齐,生成的绑定代码不保证正确性。
  2. 调用约定:仓颉文档中对于调用约定描述不清晰,其实是采用了默认的调用约定,目前 HLE 工具会尝试根据 C 代码中的函数签名推断调用约定,但是不保证正确性。
  3. 使用限制:HLE 自动生成 C 语言到仓颉的胶水代码受到系统 glibc 版本 限制,当前仅支持 Ubuntu 22.04 及以上系统。