仓颉语言与C语言互操作

为了兼容已有的生态,仓颉支持调用 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, ...): Int32main() {// call this function by `unsafe` blocklet 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 errorreturn 0
}
@C
foreign var a: Int32 = 0 // compiler error
@C
foreign class A{} // compiler error
@C
foreign interface B{} // compiler error

1.2 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) -> Unit>。CFunc 对应 C 语言的函数指针类型。这个类型为泛型类型,其泛型参数表示该 CFunc 入参和返回值类型,使用方式如下:

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

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

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

仓颉语言支持将一个 CPointer 类型的变量类型转换为一个具体的 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 并进行函数调用是危险行为,需要用户保证指针指向的是一个切实可用的函数地址,否则将发生运行时错误。

1.2 inout 参数

在仓颉中调用 CFunc 时,其实参可以使用 inout 关键字修饰,组成引用传值表达式,此时,该参数按引用传递。引用传值表达式的类型为 CPointer,其中 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 = 0unsafe {foo1(inout n)  // OKfoo2(inout n)  // OKfoo3(inout n)  // OK}var data = Data()var a = A()unsafe {foo1(inout data.n)   // OKfoo1(inout a.data.n) // Error, n is derived indirectly from instance member variables of class A}
}
  • 注意

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

1.3 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")
}

1.4 调用约定

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

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

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

@CallingConv[CDECL]   // Can be omitted in default.
foreign func rand(): Int32main() {println(rand())
}

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

1.5 类型映射

1.5.1 基础类型

仓颉与 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 语言的结构体和指针类型的映射。

1.5.2 结构体

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

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

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

@C
struct Point3D {var x: Int64 = 0var y: Int64 = 0var 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 约束。

1.5.3 指针

对于指针类型,仓颉提供 CPointer 类型来对应 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: Int64var y: Int64var z: Int64init(x: Int64, y: Int64, z: Int64) {this.x = xthis.y = ythis.z = z}
}main() {let p1 = CPointer<Point3D>() // create a CPointer with null valueif (p1.isNull()) {  // check if the pointer is nullprint("p1 is a null pointer")}let sizeofPoint3D: UIntNative = 24var p2 = unsafe { malloc(sizeofPoint3D) }    // malloc a Point3D in heapvar p3 = unsafe { CPointer<Point3D>(p2) }    // pointer type castunsafe { p3.write(Point3D(1, 2, 3)) } // write data through pointerlet p4: Point3D = unsafe { p3.read() } // read data through pointerlet p5: CPointer<Point3D> = unsafe { p3 + 1 } // offset of pointerunsafe { 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 操作,可能会导致运行时错误。

1.5.4 数组

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

  • 作为函数参数类型:

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

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),仓颉不支持包含柔性数组的结构体的映射。

1.5.5 字符串

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

  • init(p: CPointer) 通过 CPointer 构造一个 CString
  • func getChars() 获取字符串的地址,类型为 CPointer
  • 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): UIntNativemain() {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)}
}

1.5.6 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 = 0var b: Float32 = 0.0
}main() {println(sizeOf<Data>())println(alignOf<Data>())
}

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

16
8

1.6 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 = 1var ptr = CPointer<Int8>()var f: CFunc<() -> Unit> = { => println("Hello") }var f64 = 1.0foo(i32)foo(ptr)foo(f)foo(f64)
}

执行结果如下:

1
true
Hello
match failed

1.7 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` typelet 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 块中的溢出的安全性。

1.8 编译选项

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

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

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

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

给定的库文件会被直接传给链接器,库文件名的格式应为 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>): Int32func DrawCircle(circle: CPointer<Circle>): Int32func malloc(size: UIntNative): CPointer<Int8>func free(ptr: CPointer<Int8>): Unit
}@C
struct Point {var x: Int64 = 0var y: Int64 = 0
}@C
struct Circle {var x: Int64 = 0var y: Int64 = 0var r: Int64 = 0
}main() {let SIZE_OF_POINT: UIntNative = 16let SIZE_OF_CIRCLE: UIntNative = 24let 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 = 10point.y = 20unsafe { pPoint.write(point) }var circle = Circle()circle.r = 1unsafe { 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

成都百洲文化传媒有限公司专业电商服务的典范

在电商风起云涌的时代&#xff0c;成都百洲文化传媒有限公司凭借其深厚的行业经验和独特的创新思维&#xff0c;成为了众多品牌电商之路上的得力助手。今天&#xff0c;就让我们一起走进成都百洲文化传媒&#xff0c;看看他们是如何在电商领域乘风破浪&#xff0c;助力品牌实现…

个人博客文章目录索引(持续更新中...)

文章目录 一、Java基础二、Java相关三、MySql基础四、Mybatis基础及源码五、MybatisPlus基础六、Spring基础及源码七、Tomcat源码八、SpringMVC基础及源码 随着文章数量多起来&#xff0c;每次着急翻找半天&#xff0c;而是新申请的域名下来了&#xff0c;决定整理下最近几年的…

产品中心|高效能双处理器Xilinx FPGA 4通道射频收发板卡

1、产品概述 基于Xilinx XC7K325T芯片的4通道射频收发板卡&#xff0c;搭载高能效Cortex-A8内核处理器、1组16bit/2GB DDR3及1组4GB DDR3、 1组2GB Nand Flash、1路USB接口、4路高速ADC、4路高速DAC&#xff0c;支持外触发&#xff0c;外时钟。用于FPGA程序加载板卡工作温度范…

模拟题解析:

《互联网域名管理办法》第41条规定&#xff0c;域名根服务器运行机构、域名注册管理机构和域名注册服务机构应当遵守国家相关法律、法规和标准&#xff0c;落实网络与信息安全保障措施&#xff0c;配置必要的网络通信应急设备&#xff0c;建立健全网络与信息安全监测技术手段和…

springboot项目requestId设置、统一responsebody封装以及切面

利用filter设置requestId import cn.hutool.core.lang.UUID; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.s…

python实现http接口请求并解析json格式数据

在Python项目开发中&#xff0c;如果需要与其他服务进行接口调用&#xff0c;可以使用requests库来发送HTTP请求&#xff0c;并使用json库来解析JSON响应。以下是如何实现一个HTTP接口请求并解析JSON响应的步骤&#xff1a; 步骤一&#xff1a;安装requests库 如果还没有安装r…

【云原生】使用Kubectl工具详细讲解+管理集群

Kubernetes资源控制管理 文章目录 Kubernetes资源控制管理一、案例概述二、案例前置知识点2.1、Kubectl命令工具基础命令部署命令集群管理命令故障诊断和调试命令高级命令设置命令其他命令 2.2、资源清单2.2.1、名称空间级别2.2.2、集群级别2.2.3、元数据级别 2.3、资源清单常用…

8.12 矢量图层面要素单一符号使用八(形状炸裂填充)

文章目录 前言形状炸裂填充&#xff08;Shapeburst fill&#xff09;QGis设置面符号为形状炸裂填充&#xff08;Shapeburst fill&#xff09;二次开发代码实现形状炸裂填充&#xff08;Shapeburst fill&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中使用形状炸裂填…

观测云产品更新 | Pipelines、智能监控、日志数据访问等

观测云更新 Pipelines 1、Pipelines&#xff1a;支持选择中心 Pipeline 执行脚本。 2、付费计划与账单&#xff1a;新增中心 Pipeline 计费项&#xff0c;统计所有命中中心 Pipeline 处理的原始日志的数据大小。 监控 1、通知对象管理&#xff1a;新增权限控制。配置操作权…

MySQL:某个ip连接mysql失败次数过多,导致ip锁定

1 问题说明 Host is blocked because of many connection errors&#xff1b; unblock with ‘mysqladmin flush-hosts‘ 某个ip连接mysql失败次数过多&#xff0c;然后mysql这边自带的保护机制就将ip进行了封禁。这个时候有两个解决方法 &#xff08;1&#xff09;修改配置…

制造业“智改数转”背景下,产品经理考取NPDP证书的重要性

在“智改数转”&#xff08;智能化改造和数字化转型&#xff09;已成为推动制造业高质量发展的关键路径背景下&#xff0c;作为连接市场需求与产品实现的关键角色&#xff0c;产品经理的角色愈发重要。而考取NPDP&#xff08;新产品开发专业人士认证&#xff09;证书&#xff0…

Python 高级实战:基于自然语言处理的情感分析系统

前言 在大数据和人工智能迅猛发展的今天&#xff0c;自然语言处理&#xff08;NLP&#xff09;作为人工智能的重要分支&#xff0c;已经深入到我们的日常生活和工作中。情感分析作为NLP中的一个重要应用&#xff0c;广泛应用于市场分析、舆情监控和客户反馈等领域。本文将讲述…

【ai】mocap:conda 安装python3.8+ cuda+ pytorch+torchaudio、torchvision

MotionCapubuntu 18.04不知道为啥会依赖于ffmpeg 、xorg 渲染?安装pytorch就是会带上cuda cudnn 啥的pytorch【ai】tx2 nx :安装torch、torchvision for yolov5 这里就发现 pytorch和torchvision有依赖关系的,还涉及到rapidjson所以python的环境隔离很重要。核心库 - cudato…

2024年8月 PMP认证考试 7月9日正式开始报考

尊敬的各位考生&#xff1a; 经PMI和中国国际人才交流基金会研究决定&#xff0c;中国大陆地区2024年第三期PMI认证考试定于8月31日举办。 7月9日正式开始中文报考&#xff0c;在此之前需要完成英文资料注册&#xff0c;如果您想参加8月考试&#xff0c;还有最后10天报名即截止…

5G赋能安防视频监控:EasyCVR视频汇聚融合创新技术,共筑多场景安全防线

随着科技的快速发展&#xff0c;第五代移动通信技术&#xff08;5G&#xff09;已逐渐成为我们生活中的重要组成部分。其中&#xff0c;5G技术以其超高速、低延迟、大连接数的特点&#xff0c;正在深刻改变着我们的生活方式和社会运行模式。安防监控领域作为社会安全的重要组成…

P2P文件传输协议介绍

P2P文件传输协议是一种基于对等网络&#xff08;Peer-to-Peer&#xff0c;简称P2P&#xff09;的文件共享和传输技术。以下是关于P2P文件传输协议的详细介绍&#xff1a; 一、定义与原理 P2P文件传输协议允许网络中的各个节点&#xff08;即计算机或其他设备&#xff09;之间…

STM32G431系列微秒级delay(延时)函数编写

目录 前言&#xff1a; 思考&#xff1a; 代码实现&#xff1a; delay.c: delay.h: 前言&#xff1a; 最近需要用STM32G4系列的单片机做个项目&#xff0c;因为之前一直用的标准库&#xff0c;也是第一次用G4的芯片&#xff0c;所以打算先从简单的做起&#xff0c;比如说把…

深度學習筆記14-CIFAR10彩色圖片識別(Pytorch)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習紀錄博客&#x1f356; 原作者&#xff1a;K同学啊 | 接輔導、項目定制 一、我的環境 電腦系統&#xff1a;Windows 10 顯卡&#xff1a;NVIDIA GeForce GTX 1060 6GB 語言環境&#xff1a;Python 3.7.0 開發…

ThreadX简介

文章目录 1. 摘要2. ThreadX的特性2.1 免费开源2.2 安全认证级别高2.3 组件完善2.4 实时性高2.5 支持多核2.6 支持应用动态加载2.7 代码符合MISAR规范2.8 文档全面,例程丰富2.9 集成方便3. 移植示例4. 产品应用示例1. 摘要 在嵌入式系统领域,实时性能、系统稳定性以及广泛的…

Camera开发-相机输出常用数据格式

作者简介&#xff1a; 一个平凡而乐于分享的小比特&#xff0c;中南民族大学通信工程专业研究生在读&#xff0c;研究方向无线联邦学习 擅长领域&#xff1a;驱动开发&#xff0c;嵌入式软件开发&#xff0c;BSP开发 作者主页&#xff1a;一个平凡而乐于分享的小比特的个人主页…