仓颉编程语言:仓颉-C 互操作

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Dialog对话框组件 阅读详情

为了兼容已有的生态,仓颉支持调用 C 语言的函数,也支持 C 语言调用仓颉的函数。

仓颉调用 C 的函数

在仓颉中要调用 C 的函数,需要在仓颉语言中用 @C 和 foreign 关键字声明这个函数,但 @C 在修饰 foreign 声明的时候,可以省略。

举个例子,假设我们要调用 C 的 rand 和 printf 函数,它的函数签名是这样的:

// stdlib.h
int rand();

// stdio.h
int printf (const char *fmt, ...);

那么在仓颉中调用这两个函数的方式如下:

// declare the function by `foreign` keyword, and omit `@C`
foreign func rand(): Int32
foreign func printf(fmt: CString, ...): Int32

main() {
    // call this function by `unsafe` block
    let r = unsafe { rand() }
    println("random number ${r}")
    unsafe {
        var fmt = LibC.mallocCString("Hello, No.%d\n")
        printf(fmt, 1)
        LibC.free(fmt)
    }
}

需要注意的是:

  1. foreign 修饰函数声明,代表该函数为外部函数。被 foreign 修饰的函数只能有函数声明,不能有函数实现。
  2. foreign 声明的函数,参数和返回类型必须符合 C 和仓颉数据类型之间的映射关系(详见下节:类型映射)。
  3. 由于 C 侧函数很可能产生不安全操作,所以调用 foreign 修饰的函数需要被 unsafe 块包裹,否则会发生编译错误。
  4. @C 修饰的 foreign 关键字只能用来修饰函数声明,不可用来修饰其他声明,否则会发生编译错误。
  5. @C 只支持修饰 foreign 函数、top-level 作用域中的非泛型函数和 struct 类型。
  6. foreign 函数不支持命名参数和参数默认值。foreign 函数允许变长参数,使用 ...表达,只能用于参数列表的最后。变长参数均需要满足 CType 约束,但不必是同一类型。
  7. 仓颉虽然提供了栈扩容能力,但是由于 C 侧函数实际使用栈大小仓颉无法感知,所以 ffi 调用进入 C 函数后,仍然存在栈溢出的风险,需要开发者根据实际情况,修改 cjStackSize 的配置。

一些不合法的 foreign 声明的示例代码如下:

foreign func rand(): Int32 { // compiler error
    return 0
}
@C
foreign var a: Int32 = 0 // compiler error
@C
foreign class A{} // compiler error
@C
foreign interface B{} // compiler error

CFunc

仓颉中的 CFunc 指可以被 C 语言代码调用的函数,共有以下三种形式:

  1. @C 修饰的 foreign 函数
  2. @C 修饰的仓颉函数
  3. 类型为 CFunc 的 lambda 表达式,与普通的 lambda 表达式不同,CFunc lambda 不能捕获变量。
// Case 1
foreign func free(ptr: CPointer<Int8>): Unit

// Case 2
@C
func callableInC(ptr: CPointer<Int8>) {
    print("This function is defined in Cangjie.")
}

// Case 3
let f1: CFunc<(CPointer<Int8>) -> Unit> = { ptr =>
    print("This function is defined with CFunc lambda.")
}

以上三种形式声明/定义的函数的类型均为 CFunc<(CPointer<Int8>) -> Unit>。CFunc 对应 C 语言的函数指针类型。这个类型为泛型类型,其泛型参数表示该 CFunc 入参和返回值类型,使用方式如下:

foreign func atexit(cb: CFunc<() -> Unit>)

与 foreign 函数一样,其他形式的 CFunc 的参数和返回类型必须满足 CType 约束,且不支持命名参数和参数默认值。

CFunc 在仓颉代码中被调用时,需要处在 unsafe 上下文中。

仓颉语言支持将一个 CPointer<T> 类型的变量类型转换为一个具体的 CFunc,其中 CPointer 的泛型参数 T 可以是满足 CType 约束的任意类型,使用方式如下:

main() {
    var ptr = CPointer<Int8>()
    var f = CFunc<() -> Unit>(ptr)
    unsafe { f() } // core dumped when running, because the pointer is nullptr.
}

注意

将一个指针强制类型转换为 CFunc 并进行函数调用是危险行为,需要用户保证指针指向的是一个切实可用的函数地址,否则将发生运行时错误。

inout 参数

在仓颉中调用 CFunc 时,其实参可以使用 inout 关键字修饰,组成引用传值表达式,此时,该参数按引用传递。引用传值表达式的类型为 CPointer<T>,其中 T 为 inout 修饰的表达式的类型。

引用传值表达式具有以下约束:

  • 仅可用于对 CFunc 的调用处;
  • 其修饰对象的类型必须满足 CType 约束,但不可以是 CString;
  • 其修饰对象不可以是用 let 定义的,不可以是字面量、入参、其他表达式的值等临时变量;
  • 通过仓颉侧引用传值表达式传递到 C 侧的指针,仅保证在函数调用期间有效,即此种场景下 C 侧不应该保存指针以留作后用。

inout 修饰的变量,可以是定义在 top-level 作用域中的变量、局部变量、struct 中的成员变量,但不能直接或间接来源于 class 的实例成员变量。

下面是一个例子:

foreign func foo1(ptr: CPointer<Int32>): Unit

@C
func foo2(ptr: CPointer<Int32>): Unit {
    let n = unsafe { ptr.read() }
    println("*ptr = ${n}")
}

let foo3: CFunc<(CPointer<Int32>) -> Unit> = { ptr =>
    let n = unsafe { ptr.read() }
    println("*ptr = ${n}")
}

struct Data {
    var n: Int32 = 0
}

class A {
    var data = Data()
}

main() {
    var n: Int32 = 0
    unsafe {
        foo1(inout n)  // OK
        foo2(inout n)  // OK
        foo3(inout n)  // OK
    }
    var data = Data()
    var a = A()
    unsafe {
        foo1(inout data.n)   // OK
        foo1(inout a.data.n) // Error, n is derived indirectly from instance member variables of class A
    }
}

注意

使用宏扩展特性时,在宏的定义中,暂时不能使用 inout 参数特性。

unsafe

在引入与 C 语言的互操作过程中,同时也引入了 C 的许多不安全因素,因此在仓颉中使用 unsafe 关键字,用于对跨 C 调用的不安全行为进行标识。

关于 unsafe 关键字,有以下几点说明:

  • unsafe 可以修饰函数、表达式,也可以修饰一段作用域。
  • 被 @C 修饰的函数,被调用处需要在 unsafe 上下文中。
  • 在调用 CFunc 时,使用处需要在 unsafe 上下文中。
  • foreign 函数在仓颉中进行调用,被调用处需要在 unsafe 上下文中。
  • 当被调用函数被 unsafe 修饰时,被调用处需要在 unsafe 上下文中。

使用方式如下:

foreign func rand(): Int32

@C
func foo(): Unit {
    println("foo")
}

var foo1: CFunc<() -> Unit> = { =>
    println("foo1")
}

main(): Int64 {
    unsafe {
        rand()           // Call foreign func.
        foo()            // Call @C func.
        foo1()           // Call CFunc var.
    }
    0
}

需要注意的是,普通 lambda 无法传递 unsafe 属性,当 unsafe 的 lambda 逃逸后,可以不在 unsafe 上下文中直接调用而未产生任何编译错误。当需要在 lambda 中调用 unsafe 函数时,建议在 unsafe 块中进行调用,参考如下用例:

unsafe func A(){}
unsafe func B(){
    var f = { =>
        unsafe { A() } // Avoid calling A() directly without unsafe in a normal lambda.
    }  
    return f  
}
main() {
    var f = unsafe{ B() }
    f()
    println("Hello World")
}

调用约定

函数调用约定描述调用者和被调用者双方如何进行函数调用(如参数如何传递、栈由谁清理等),函数调用和被调用双方必须使用相同的调用约定才能正常运行。仓颉编程语言通过 @CallingConv 来表示各种调用约定,支持的调用约定如下:

  • CDECL, CDECL 表示 clang 的 C 编译器在不同平台上默认使用的调用约定。
  • STDCALL, STDCALL 表示 Win32 API 使用的调用约定。

通过 C 语言互操作机制调用的 C 函数,未指定调用约定时将采用默认的 CDECL 调用约定。如下调用 C 标准库函数 rand 示例:

@CallingConv[CDECL]   // Can be omitted in default.
foreign func rand(): Int32

main() {
    println(rand())
}

@CallingConv 只能用于修饰 foreign 块、单个 foreign 函数和 top-level 作用域中的 CFunc 函数。当 @CallingConv 修饰 foreign 块时,会为 foreign 块中的每个函数分别加上相同的 @CallingConv 修饰。

类型映射

基础类型

仓颉与 C 语言支持基本数据类型的映射,总体原则是:

  1. 仓颉的类型不包含指向托管内存的引用类型;
  2. 仓颉的类型和 C 的类型具有同样的内存布局。

比如说,一些基本的类型映射关系如下:

Cangjie TypeC TypeSize (byte)
Unitvoid0
Boolbool1
UInt8char1
Int8int8_t1
UInt8uint8_t1
Int16int16_t2
UInt16uint16_t2
Int32int32_t4
UInt32uint32_t4
Int64int64_t8
UInt64uint64_t8
IntNativessize_tplatform dependent
UIntNativesize_tplatform dependent
Float32float4
Float64double8

说明

int 类型、long 类型等由于其在不同平台上的不确定性,需要程序员自行指定对应仓颉编程语言类型。在 C 互操作场景中,与 C 语言类似,Unit 类型仅可作为 CFunc 中的返回类型和 CPointer 的泛型参数。

仓颉也支持与 C 语言的结构体和指针类型的映射。

结构体

对于结构体类型,仓颉用 @C 修饰的 struct 来对应。比如说 C 语言里面有这样的一个结构体:

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

那么它对应的仓颉类型可以这么定义:

@C
struct Point3D {
    var x: Int64 = 0
    var y: Int64 = 0
    var z: Int64 = 0
}

如果 C 语言里有这样的一个函数:

Point3D addPoint(Point3D p1, Point3D p2);

那么对应的,在仓颉里面可以这样声明这个函数:

foreign func addPoint(p1: Point3D, p2: Point3D): Point3D

用 @C 修饰的 struct 必须满足以下限制:

  • 成员变量的类型必须满足 CType 约束
  • 不能实现或者扩展 interfaces
  • 不能作为 enum 的关联值类型
  • 不允许被闭包捕获
  • 不能具有泛型参数

用 @C 修饰的 struct 自动满足 CType 约束。

指针

对于指针类型,仓颉提供 CPointer<T> 类型来对应 C 侧的指针类型,其泛型参数 T 需要满足 CType 约束。比如对于 malloc 函数,在 C 里面的签名为:

void* malloc(size_t size);

那么在仓颉中,它可以声明为:

foreign func malloc(size: UIntNative): CPointer<Unit>

CPointer 可以进行读写、偏移计算、判空以及转为指针的整型形式等,详细 API 可以参考《仓颉编程语言库 API》。其中读写和偏移计算为不安全行为,当不合法的指针调用这些函数时,可能发生未定义行为,这些 unsafe 函数需要在

unsafe 块中调用。

CPointer 的使用示例如下:

foreign func malloc(size: UIntNative): CPointer<Unit>
foreign func free(ptr: CPointer<Unit>): Unit

@C
struct Point3D {
    var x: Int64
    var y: Int64
    var z: Int64

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

main() {
    let p1 = CPointer<Point3D>() // create a CPointer with null value
    if (p1.isNull()) {  // check if the pointer is null
        print("p1 is a null pointer")
    }

    let sizeofPoint3D: UIntNative = 24
    var p2 = unsafe { malloc(sizeofPoint3D) }    // malloc a Point3D in heap
    var p3 = unsafe { CPointer<Point3D>(p2) }    // pointer type cast

    unsafe { p3.write(Point3D(1, 2, 3)) } // write data through pointer

    let p4: Point3D = unsafe { p3.read() } // read data through pointer

    let p5: CPointer<Point3D> = unsafe { p3 + 1 } // offset of pointer

    unsafe { free(p2) }
}

仓颉语言支持 CPointer 之间的强制类型转换,转换前后的 CPointer 的泛型参数 T 均需要满足 CType 的约束,使用方式如下:

main() {
    var pInt8 = CPointer<Int8>()
    var pUInt8 = CPointer<UInt8>(pInt8) // CPointer<Int8> convert to CPointer<UInt8>
    0
}

仓颉语言支持将一个 CFunc 类型的变量类型转换为一个具体的 CPointer,其中 CPointer 的泛型参数 T 可以是满足 CType 约束的任意类型,使用方式如下:

foreign func rand(): Int32
main() {
    var ptr = CPointer<Int8>(rand)
    0
}

注意

将一个 CFunc 强制类型转换为指针通常是安全的,但是不应该对转换后的指针执行任何的 read,write 操作,可能会导致运行时错误。

数组

仓颉使用 VArray 类型与 C 的数组类型映射,VArray 可以用户作为函数参数和 @C struct 成员。当 VArray<T, $N> 中的元素类型 T 满足 CType 约束时, VArray<T, $N> 类型也满足 CType 约束。

作为函数参数类型:

当 VArray 作为 CFunc 的参数时, CFunc 的函数签名仅可以是 CPointer<T> 类型或 VArray<T, $N> 类型。当函数签名中的参数类型为 VArray<T, $N> 时,传递的参数仍以 CPointer<T> 形式传递。

VArray 作为参数的使用示例如下:

foreign func cfoo1(a: CPointer<Int32>):Unit
foreign func cfoo2(a: VArray<Int32, $3): Unit

对应的 C 侧函数定义可以是:

void cfoo1(int *a) { ... }
void cfoo2(int a[3]) { ... }

调用 CFunc 时,需要通过 inout 修饰 VArray 类型变量:

var a: VArray<Int32, $3> = [1, 2, 3]
unsafe {
    cfoo1(inout a)
    cfoo2(inout a)
}

VArray 不允许作为 CFunc 的返回值类型。

作为 @C struct 成员:

当 VArray 作为 @C struct 成员时,它的内存布局与 C 侧的结构体排布一致,需要保证仓颉侧声明长度与类型也与 C 完全一致:

struct S {
    int a[2];
    int b[0];
}

在仓颉中,可以声明为如下结构体与 C 代码对应:

@C
struct S {
    var a = VArray<Int32, $2>(item: 0)
    var b = VArray<Int32, $0>(item: 0)
}

注意

C 语言中允许结构体的最后一个字段为未指明长度的数组类型,该数组被称为柔性数组(flexible array),仓颉不支持包含柔性数组的结构体的映射。

字符串

特别地,对于 C 语言中的字符串类型,仓颉中设计了一个 CString 类型来对应。为简化为 C 语言字符串的操作,CString 提供了以下成员函数:

  • init(p: CPointer<UInt8>) 通过 CPointer 构造一个 CString
  • func getChars() 获取字符串的地址,类型为 CPointer<UInt8>
  • func size(): Int64 计算该字符串的长度
  • func isEmpty(): Bool 判断该字符串的长度是否为 0,如果字符串的指针为空返回 true
  • func isNotEmpty(): Bool 判断该字符串的长度是否不为 0,如果字符串的指针为空返回 false
  • func isNull(): Bool 判断该字符串的指针是否为 null
  • func startsWith(str: CString): Bool 判断该字符串是否以 str 开头
  • func endsWith(str: CString): Bool 判断该字符串是否以 str 结尾
  • func equals(rhs: CString): Bool 判断该字符串是否与 rhs 相等
  • func equalsLower(rhs: CString): Bool 判断该字符串是否与 rhs 相等,忽略大小写
  • func subCString(start: UInt64): CString 从 start 开始截取子串,返回的子串存储在新分配的空间中
  • func subCString(start: UInt64, len: UInt64): CString 从 start 开始截取长度为 len 的子串,返回的子串存储在新分配的空间中
  • func compare(str: CString): Int32 该字符串与 str 比较,返回结果与 C 语言的 strcmp(this, str) 一样
  • func toString(): String 用该字符串构造一个新的 String 对象
  • func asResource(): CStringResource 获取 CString 的 Resource 类型

另外,将 String 类型转换为 CString 类型,可以通过调用 LibC 中的 mallocCString 接口,使用完成后需要对 CString 进行释放。

CString 的使用示例如下:

foreign func strlen(s: CString): UIntNative

main() {
    var s1 = unsafe { LibC.mallocCString("hello") }
    var s2 = unsafe { LibC.mallocCString("world") }

    let t1: Int64 = s1.size()
    let t2: Bool = s2.isEmpty()
    let t3: Bool = s1.equals(s2)
    let t4: Bool = s1.startsWith(s2)
    let t5: Int32 = s1.compare(s2)

    let length = unsafe { strlen(s1) }

    unsafe {
        LibC.free(s1)
        LibC.free(s2)
    }
}

sizeOf/alignOf

仓颉还提供了 sizeOf 和 alignOf 两个函数,用于获取上述 C 互操作类型的内存占用和内存对齐数值(单位:字节),函数声明如下:

public func sizeOf<T>(): UIntNative where T <: CType
public func alignOf<T>(): UIntNative where T <: CType

使用示例:

@C
struct Data {
    var a: Int64 = 0
    var b: Float32 = 0.0
}

main() {
    println(sizeOf<Data>())
    println(alignOf<Data>())
}

在 64 位机器上运行,将输出:

16
8

CType

除类型映射一节提供的与 C 侧类型进行映射的类型外,仓颉还提供了一个 CType 接口,接口本身不包含任何方法,它可以作为所有 C 互操作支持的类型的父类型,便于在泛型约束中使用。

需要注意的是:

  1. CType 接口是仓颉中的一个接口类型,它本身不满足 CType 约束;
  2. CType 接口不允许被继承、扩展;
  3. CType 接口不会突破子类型的使用限制。

CType 的使用示例如下:

func foo<T>(x: T): Unit where T <: CType {
    match (x) {
        case i32: Int32 => println(i32)
        case ptr: CPointer<Int8> => println(ptr.isNull())
        case f: CFunc<() -> Unit> => unsafe { f() }
        case _ => println("match failed")
    }
}

main() {
    var i32: Int32 = 1
    var ptr = CPointer<Int8>()
    var f: CFunc<() -> Unit> = { => println("Hello") }
    var f64 = 1.0
    foo(i32)
    foo(ptr)
    foo(f)
    foo(f64)
}

执行结果如下:

1
true
Hello
match failed

C 调用仓颉的函数

仓颉提供 CFunc 类型来对应 C 侧的函数指针类型。C 侧的函数指针可以传递到仓颉,仓颉也可以构造出对应 C 的函数指针的变量传递到 C 侧。

假设一个 C 的库 API 如下:

typedef void (*callback)(int);
void set_callback(callback cb);

对应的,在仓颉里面这个函数可以声明为:

foreign func set_callback(cb: CFunc<(Int32) -> Unit>): Unit

CFunc 类型的变量可以从 C 侧传递过来,也可以在仓颉侧构造出来。在仓颉侧构造 CFunc 类型有两种办法,一个是用 @C 修饰的函数,另外一个是标记为 CFunc 类型的闭包。

@C 修饰的函数,表明它的函数签名是满足 C 的调用规则的,定义还是写在仓颉这边。foreign 修饰的函数定义是在 C 侧的。

注意

foreign 修饰的函数与 @C 修饰的函数,这两种 CFunc 的命名不建议使用 CJ_(不区分大小写)作为前缀,否则可能与标准库及运行时等编译器内部符号出现冲突,导致未定义行为。

示例如下:

@C
func myCallback(s: Int32): Unit {
    println("handle ${s} in callback")
}

main() {
    // the argument is a function qualified by `@C`
    unsafe { set_callback(myCallback) }

    // the argument is a lambda with `CFunc` type
    let f: CFunc<(Int32) -> Unit> = { i => "handle ${i} in callback" }
    unsafe { set_callback(f) }
}

假设 C 函数编译出来的库是 "libmyfunc.so",那么需要使用 cjc -L. -lmyfunc test.cj -o test.out 编译命令,使仓颉编译器去链接这个库。最终就能生成想要的可执行程序。

另外,在编译 C 代码时,请打开 -fstack-protector-all/-fstack-protector-strong 栈保护选项,仓颉侧代码默认拥有溢出检查与栈保护功能。在引入 C 代码后,需要同步保证 unsafe 块中的溢出的安全性。

编译选项

使用 C 互操作通常需要手动链接 C 的库,仓颉编译器提供了相应的编译选项。

  • --library-path <value>, -L <value>, -L<value>:指定要链接的库文件所在的目录。

    --library-path <value> 指定的路径会被加入链接器的库文件搜索路径。另外环境变量 LIBRARY_PATH 中指定的路径也会被加入链接器的库文件搜索路径中,通过 --library-path 指定的路径会比 LIBRARY_PATH 中的路径拥有更高的优先级。

  • --library <value>, -l <value>, -l<value>:指定要链接的库文件。

    给定的库文件会被直接传给链接器,库文件名的格式应为 lib[arg].[extension]。

关于仓颉编译器支持的所有编译选项,详见cjc 编译选项。

示例

假设我们有一个 C 库 libpaint.so,其头文件如下:

include <stdint.h>

typedef struct {
    int64_t x;
    int64_t y;
} Point;

typedef struct {
    int64_t x;
    int64_t y;
    int64_t r;
} Circle;

int32_t DrawPoint(const Point* point);
int32_t DrawCircle(const Circle* circle);

在仓颉代码中使用该 C 库的示例代码如下:

// main.cj
foreign {
    func DrawPoint(point: CPointer<Point>): Int32
    func DrawCircle(circle: CPointer<Circle>): Int32

    func malloc(size: UIntNative): CPointer<Int8>
    func free(ptr: CPointer<Int8>): Unit
}

@C
struct Point {
    var x: Int64 = 0
    var y: Int64 = 0
}

@C
struct Circle {
    var x: Int64 = 0
    var y: Int64 = 0
    var r: Int64 = 0
}

main() {
    let SIZE_OF_POINT: UIntNative = 16
    let SIZE_OF_CIRCLE: UIntNative = 24
    let ptr1 = unsafe { malloc(SIZE_OF_POINT) }
    let ptr2 = unsafe { malloc(SIZE_OF_CIRCLE) }

    let pPoint = CPointer<Point>(ptr1)
    let pCircle = CPointer<Circle>(ptr2)

    var point = Point()
    point.x = 10
    point.y = 20
    unsafe { pPoint.write(point) }

    var circle = Circle()
    circle.r = 1
    unsafe { pCircle.write(circle) }

    unsafe {
        DrawPoint(pPoint)
        DrawCircle(pCircle)

        free(ptr1)
        free(ptr2)
    }
}

编译仓颉代码的命令如下:

cjc -L . -l paint ./main.cj

其中编译命令中 -L . 表示链接库时从当前目录查找(假设 libpaint.so 存在于当前目录),-l paint 表示链接的库的名字,编译成功后默认生成二进制文件 main,执行二进制文件的命令如下:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
鸿蒙HarmonyOS应用开发之C/C++标准库机制概述 OpenHarmony NDK提供业界标准库 libc标准库、 C++标准库 ,本文用于介绍C/C++标准库在OpenHarmony中的机制,开发者了解这些机制有助于在NDK开发过程中避免相关问题。 阅读详情

相关推荐

仓颉编程语言:基本概念

在以上程序中,if 表达式作为变量定义的初值使用,由于变量 bit 没有被标注类型、需要从初值中推导,所以 if 表达式的类型取为两个分支代码块类型的最小公共父类型,根据前文对“代码块”的介绍,可知两个分支代码块类型都是 Int8,所以 if 表达式的类型被确定为 Int8,其值为所执行分支即 else 分支代码块的值,所以变量 bit 的类型为 Int8、值为 1。在仓颉程序中,由一对大括号“{}”包围起来的一组表达式,被称为“代码块”,它将作为程序的一个顺序执行流,其中的表达式将按编码顺序依次执行。

啥也不会的云计算小白 3124

仓颉语言与C语言互操作

为了兼容已有的生态,仓颉支持调用 C 语言的函数,也支持 C 语言调用仓颉的函数。

程小二的博客 2310

鸿蒙应用开发之仓颉编程语言基础

仓颉编程语言是华为公司独立研发并开源的一种面向全场景应用开发的通用编程语言,可以兼顾开发效率和运行性能,并提供良好的编程体验。

sinat_30844883的博客 2904

仓颉编程语言来了-仓颉编程语言白皮书

卓越性能:仓颉编译器及运行时从全栈对编译进行优化,包括编译器前端基于CHIR(Cangjie HighLevel IR)高层编译优化(比如语义感知的循环优化、语义感知的后端协同优化等),基于后端的编译优化(比如:SLP向量化、Intrinsic优化、InlineCache、过程间指针优化、Barrier优化等),基于运行时的优化(比如轻量锁、分布式标记、并发Tracing优化等),一系列的优化让仓颉充分发挥处理器能力,为应用提供卓越的性能支持。此外,仓颉还支持类型推断,能够降低开发者类型标注的负担;

Neo的博客 4338

仓颉编程语言技术深度解析-入门到高手【好书推荐】

在面向对象编程的内容中,介绍了类的定义和创建对象的方法,详细讲解了面向对象编程的三大特征:封装、继承和多态。同时,仓颉社区也为开发者提供了丰富的资源和良好的社区环境,进一步推动了仓颉语言的发展和应用。例如,北京理工大学以“30+30”两个特班为基础,深度协同校企资源,将仓颉语言融入专业课堂和教材,构建课题方向、课程教学、实践实训合一的教学实践体系。仓颉语言可以很好地应对目前的变化,在《图解仓颉编程:高级篇》这本书中,就以全彩风格、丰富的图表展示仓颉的高级特性。在他们的倾力分享下,小白也能轻松学会仓颉编程。

一键难忘的博客 5349

[技术解析]4DGS:突破实时动态渲染的4D高斯溅射技术

本文深入解析了4DGS(4D Gaussian Splatting)技术,它通过引入时间维度,将静态的3D高斯溅射升级为动态的4D表示,实现了对复杂动态场景的高质量实时渲染。该技术利用时空联合编码器与高斯形变场网络,结合多分辨率编码与差分溅射渲染,在VR/AR、高帧率游戏等领域展现出突破性的应用潜力,兼顾了渲染速度与画面稳定性。

weixin_29218509的博客 417

华为自研编程语言“仓颉”来了!鸿蒙应用开发新语言,性能优于 Java、Go、Swift

在今天刚刚召开的华为开发者大会(HDC 2024)上,华为内部研发已久的国产自主编程语言仓颉终于正式对外官宣!随着万物互联以及智能时代的到来,软件的形态将发生巨大的变化。一方面,移动应用和移动互联网领域仍然强力驱动人机交互、设备协同、智能化、安全性等方向的创新,另一方面人工智能也同样驱动软件朝智能化、端边云协同等方向演进。新技术、新场景下应用软件的开发对编程语言提出了新的诉求和挑战。

IT界那些事儿 5987

保姆级教程:用NFS把群晖NAS的文件夹挂到Ubuntu 22.04上,实现文件无缝共享

本文提供了一份详细的教程,指导用户如何通过NFS协议将群晖NAS的文件夹挂载到Ubuntu 22.04系统上,实现文件的无缝共享。文章对比了NFS与SMB协议的性能差异,并提供了群晖端和Ubuntu端的配置指南、高级参数优化、自动挂载方案以及生产环境中的实战技巧,帮助用户提升文件共享效率和系统稳定性。

weixin_29213827的博客 408

论文速览 | 仓颉编程语言概览

仓颉语言通过支持多范式编程、增强型双向类型推断、CHIR中间表示、LLVM扩展后端与并发压缩式GC的协同设计,实现了简洁性、安全性、可扩展性与性能的平衡,在执行性能、GC延迟、内存占用及跨语言互操作效率上较现有主流应用级语言呈现出一定优势,面向移动应用开发所面临的资源约束、低延迟需求等核心问题取得了较大进展。引入类型扩展机制实现现有类型的功能扩展与接口实现,支持宏编程、注解、反射等元编程机制,原生支持C语言互操作(通过@C注解与unsafe上下文)。论文服务,如果您对我们的论文感兴趣,请后台私信“

pl_lab_001的博客 461

史上最小白之RNN详解

1.前言 网上目前已经有诸多优秀的RNN相关博客,但是我写博客的出发点主要是为了加深和巩固自己的理解,所以还是决定自己再进行一下总结和描述,如有不正确的地方欢迎指正~ 2.区分RNN 循环神经网络(Recurrent Neural Network),递归神经网络(Recursive Neural Network),你有没有发现他们的缩写都是RNN,那他们两个是同一回事儿吗?网上有一些博客把这两就当...

Tink1995的博客 4万+

Power domain 划分该如何下手

假如PD1比PD3更always on的话,我们只需要插入普通buffer即可,因为PD3 on,PD1也肯定是ON,PD1 off,PD3肯定时off,PD1能cover PD3的电源情况,因此使用普通buffer也可,但是处于省电角度,我们还是使用AO buffer;在我们做多power domain时,在切分power domain时,需要谨慎,稍有不慎,就会出现congestion以及timing问题,那问题来了,我们在切分power domain时有什么考究么,今天小编就和大家一起讨论讨论。

芯冰乐 207

仓颉编程语言入门

五年磨一剑,华为仓颉编程语言正式发布。

程小二的博客 4万+

AI上推荐 之 多任务loss优化(自适应权重篇)

1. 写在前面 在多任务学习中,往往会将多个相关的任务放在一起来学习。例如在推荐系统中,排序模型同时预估候选的点击率和浏览时间。相对于单任务学习,多任务学习有以下优势: 多个任务共享一个模型,占用内存量减少; 多个任务一次前向计算得出结果,推理速度增加; 关联任务通过共享信息,相互补充,可以提升彼此的表现。 前面的一篇文章,主要是从模型结构的角度聊了下多任务学习,介绍了工业界非常经典也常用的MMOE模型,然而,对于多任务学习, Loss的优化也非常重要, 因为我们知道通过多个目标去指导网络进行统一的训练

Miracle8070 1万+

仓颉编程语言:仓颉-ArkTS 互操作

在 OpenHarmony 系统上,ArkTS 具备完整广泛的生态,为复用 ArkTS 生态,仓颉支持与 ArkTS 高效跨语言互通。

Androidbye的博客 1532

28、沉浸式体验技术:概念、类型与应用

本文全面介绍了沉浸式体验技术的概念、类型与应用。从双边滤波器的图像处理原理切入,系统阐述了VR、AR、MR、ER及数字孪生等核心技术的特点与区别,并通过丰富案例展示了其在商业、医疗、教育、旅游、房地产、物流等多个领域的实际应用。文章还分析了技术融合趋势、硬件升级方向、应用场景拓展潜力,同时探讨了数据处理、网络延迟、隐私安全等挑战及应对策略,最后以流程图和对比表格总结技术发展脉络,展望沉浸式技术推动社会进步的广阔前景。

wind6的博客 386

【Power Compiler手册】4.saif文件

功耗计算的准确性取决于切换活动数据的准确性。这些数据是通过使用RTL仿真或门级仿真生成的,并存储在SAIF文件中。在执行功耗优化和分析之前,应该使用SAIF文件来反标设计对象上的切换活动信息。SAIF是由Synopsys支持的ASCII格式,用于促进不同Synopsys工具之间的信息交换(参见IEEE 1801标准,附录J)。使用`read_saif`命令读取SAIF文件,使用`write_saif`命令写出SAIF文件。有关更多信息,请参见`read_saif`和`write_saif`命令的手册页。

QRBQ 2189

华为仓颉编程语言正式发布,仓颉编程教程

华为在 2024 年 6 月 21 日的华为开发者大会上,华为终端 BG 软件部总裁龚体正式官宣了华为自研仓颉编程语言,并发布了 HarmonyOS NEXT 仓颉语言开发者预览版。仓颉 | 华为开发者联盟仓颉编程语言文件后缀名为.cj你好,仓颉。lambda表达式可以让函数的创建和使用更加灵活,lambda表达式的值就是一个匿名函数仓颉提供了Exception和Error两个类型,用于描述程序运行时的异常行为开发者可以继承Exception或其子类来自定义异常类,但不能继承Error或其子类。

shixuyong的博客 4408

PrimeTime low power-多电压设计流程(1)

PrimeTime支持使用IEEE 1801统一电源格式(UPF)标准来指定设计的多电压特性。PrimeTime能够在多电压供电和使用set_voltage命令在特定电源网上设置电压值的情况下,正确分析设计的时序。要了解如何使用多电压设计流程,请参考以下内容:- 多电压分析需求- 指定电源连接性- UPF命令- GoldenUPF流程- 多重电源电压分析。

QRBQ 529

仓颉编程语言开发指南(下)

文章目录仓颉编程语言开发指南(上)十五、宏1.宏的简介2.Tokens 相关类型和 quote 表达式Token 类型Tokens 类型quote 表达式和插值3.语法节点节点的解析使用解析表达式和声明的函数使用构造函数进行解析节点的组成部分BinaryExpr 案例FuncDecl 案例使用 quote 插值语法节点4.宏的实现非属性宏属性宏嵌套宏宏定义中嵌套宏调用宏调用中嵌套宏调用嵌套宏之间的消息传递5.编译、报错与调试宏的编译和使用并行宏展开diagReport 报错机制使用 --debug-macr

欢迎来到我的学习笔记薄 2994

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

华为仓颉编程语言

仓颉编程语言是华为公司自主研发的一款静态强类型、编译型语言,具备高效编程、安全可靠、轻松并发和卓越性能等特点。该语言旨在解决全场景应用开发中的挑战,为开发者提供友好的开发体验和卓越的程序性能。自2019年启动研发以来,仓颉编程语言已经历了五年的沉淀和大量研发投入,目前已正式开启开发者预览版。

了不起的小白君的博客 4174

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

当现代教育技术遇上仓颉---探秘华为仓颉编程语言与未来教育技术的接轨

仓颉编程语言是华为推出的一款高性能编程语言,旨在面向未来的分布式计算环境和硬件生态系统。高效性:语法简洁,优化了运行效率。可移植性:支持多种平台,从嵌入式设备到云计算环境均可适配。与硬件深度结合:面向华为自研芯片(如昇腾、鲲鹏等)的优化。多语言互操作:支持与C、C++、Python等主流语言互操作。以下是一个简单的仓颉语言代码示例,用于展示其基本语法和功能。此代码模拟了一个小型 HTTP 服务,适用于网络编程课程或实训项目中的基础教学。

2406_83947720的博客 2312

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

华为明年将推出自研编程语言仓颉

9月25日午间消息,在今日的华为全联接大会2021上,华为副总裁、计算产品线总裁邓泰华接受媒体采访。 今日,华为发布了欧拉的全新版本。据悉,OpenEuler与OpenHarmony将能力共享、生态互通。 目前两个操作系统的内核技术已经共享,未来还将在安全OS,编程语言,设备驱动框架,分布式软总线方面能力共享;生态方面,将实现应用生态、设备生态、开发者生态、高校生态上的互通。 邓泰华在采访中表示,华为明年将推出自研的编程语言仓颉,将鸿蒙和欧拉在应用开发生态上进行打通。 实际上,2020年华为就曾..

m0_46163918的博客 1万+

使用仓颉编程语言是一种怎样的体验?

摘要:华为在2024开发者大会上正式发布自研仓颉编程语言及HarmonyOS NEXT预览版,这款历时5年研发的新语言融合现代特性与编译优化,提供高效开发体验。开发者评价其兼具函数式与OOP优势,在元编程、静态编译等方面表现突出,但生态工具仍需完善。与C#等成熟语言对比,仓颉在语法简洁性上具有优势,实际性能有待验证。早期使用者分享从质疑到认可的心路历程,认为伴随新语言成长具有独特价值。目前仓颉尚未开源,其跨平台能力与社区生态建设将是未来发展关键。(149字)

2532

华为仓颉|新一代高性能编程语言

华为公司推出了自有的编程语言——仓颉(Cangjie)。这款语言定位于高性能计算和高安全性应用,旨在解决现代开发中的一系列痛点。小编经过两天的漫长等待后,终于通过审核,拿到了仓颉编译工具。现在华哥就给大家来开箱体验下。仓颉支持多种基本数据类型,包括整数、浮点数、布尔值、字符串等。整数类型:用于表示整数值,可以是有符号或无符号。浮点数类型:用于表示带有小数点的数值。布尔类型:用于表示逻辑真或假。字符串类型:用于表示文本数据。以冒号引出类型定义,这点跟typecript很像。

liyunhua258的博客 5405

探索仓颉编程语言:官网上线,在线体验与版本下载全面启航

在编程语言的浩瀚星海中,新星正在冉冉升起。仓颉编程语言,以其独特的魅力和创新的理念,吸引了全球开发者的目光。随着仓颉编程语言官网的正式上线,我们迎来了一个全新的探索旅程,一个能够让开发者深入了解和体验仓颉语言的世界。在这里,我们不仅提供了仓颉编程语言的软件包和集成开发环境(IDE)的下载,还有详尽的安装指南,更有在线体验功能,让开发者能够即刻上手,感受仓颉语言的无限可能。此次官网的上线,标志着仓颉编程语言向更广泛的开发者社区敞开了大门。

从事移动开发八年,csdn博客专家,阿里云特邀专家,华为云云享专家,高级网络信息安全工程师,大数据工程师(高级),python技术开发(高级),HarmonyOS 应用开发者高级认证,现在某学校任教。 1万+

跟我一起学“仓颉”编程语言-跨语言互操作

本章为大家详细的介绍了仓颉编程语言中跨语言互操作的内容。

Cool_foolisher的博客 1166
上一篇: 仓颉编程语言:宏的使用案例
下一篇: 仓颉编程语言:仓颉-ArkTS 互操作
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值