首頁 > 軟體

Go 語言中執行 C程式 程式碼 

2022-03-22 19:00:57

前言:

在前面多篇 Go 系列文章中,我們瞭解到,Go 語言脫胎於 C 語言,這就意味著在某些更底層的細節中,我們可以使用 C 語言實現,然後通過 Go 來呼叫相關的 C 程式碼。其實這一特點,在 Java 的 JVM、Python 的直譯器也是通過底層是直接呼叫 C 實現的。

而本篇文章就來學習一下,如何在 Go 語言中執行 C 程式。

一、直接在 Go 程式碼中寫入 C 程式

Go 語言通過 cgo 工具來識別程式碼中的 C 語言,我們可以通過命令 ​​go env​​ 來檢視是否 cgo 工具是否開啟。

​​CGO_ENABLED=1​​ 表示 cgo 工具可用,當設定為 0 時,表示工具不可用。

然後我可以新建一個​​CinGo.go​​​ 的程式,然後在註釋中寫入 c 語言的程式碼。然後匯入 Go 提供的 c 包 ​​import "C"​​ ,Go 語言在看到匯入這個包之後就知道如何去處理註釋中的內容了。

這裡我們在 C 程式碼中寫入要給 ​​callC()​​ 函數,然後在 Go 語言中進行呼叫:

package main

// #include <stdio.h>
// void callC() {
//   printf("Hello World from C!n");
// }
import "C"
import "fmt"

func main() {

  fmt.Println("讓我們學習 Go 語句呼叫 C 程式")
  C.callC()
  fmt.Println("呼叫 C 程式結束")
}

執行結果:

$ go run CinGo.go
讓我們學習 Go 語句呼叫 C 程式
Hello World from C!;'/;'  
呼叫 C 程式結束

但是,這種方式的 C 程式碼和 Go 語言程式碼在同一個檔案中,所以大家能明顯發現這種方式的程式碼耦合度太高,僅僅適用於專案簡單單一的情形。

一個更合理的方式應該是 C 程式碼單獨在一個檔案。

二、Go 直接呼叫 C 檔案

那麼,如果已經寫好一個封裝好的 C 檔案程式碼,Go 語言該如何呼叫呢?

此時我們需要直接寫好 C 程式碼,因為 Go 程式碼是無法對 C 程式碼檔案進行重寫或者修改的。

​寫好 C 標頭檔案​

我們在本地 Go 專案中,建立一個 ​​hello.h​​ 的標頭檔案,

程式碼如下:

#ifndef HELLO_H
#define HELLO_H

int sayHello(const char *name, char *out);
void printMessage(char *message);
void cHello();
int add(int a, int b);

#endif

​編寫 C 檔案​

然後編寫 ​​hello.c​​ 檔案,如下:

#include "hello.h"
#include <stdio.h>

int sayHello(const char *name, char *out) {
    int n;

    n = sprintf(out, "Hello, My name is %s!", name);

    return n;
}

void cHello() {
    printf("Hello from C!n");
}

void printMessage(char* message) {
    printf("從 Go 語言接收的資訊: %sn", message);
}

int add(int a, int b) {
    return a + b;
}

​寫好 Go 程式碼​

最後編寫我們的 ​​main.go​​ 語言:

  • 我們需要在 CFLAGS 引數中填入我們的 GOPath 路徑,​​#cgo CFLAGS: -I /Users/yuzhou_1su/go/src/CinGo​​
  • 然後在 LSFLAGS 中填入我們的 C 編譯後的本地連結檔案:​​#cgo LDFLAGS: /Users/yuzhou_1su/go/src/CinGo/hello.a​​ 
package main

// #cgo CFLAGS: -I /Users/yuzhou_1su/go/src/CinGo
// #cgo LDFLAGS: /Users/yuzhou_1su/go/src/CinGo/hello.a
// #include <stdlib.h>
// #include <hello.h>
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {

    C.cHello()

    a := C.int(1024)
    b := C.int(2022)
    result := C.add(a, b)
    fmt.Println("Reuslt is:", result)

    goMessage := C.CString("This is Go")
    defer C.free(unsafe.Pointer(goMessage))
    C.printMessage(goMessage)

}

​最後程式碼結構如下:

然後我們首先編譯 c 程式碼:

$ gcc -c *.c      

$ /usr/bin/ar rs hello.a *.o
ar: creating archive hello.a
$ rm hello.o

然後再執行 Go 程式碼,結果如下:

$ go run main.go         
Hello from C!
Reuslt is: 3046

從 Go 語言接收的資訊: This is Go

總結:

在編寫上述的小案例過程你中的,都出現了了很多小問題,比如 C 程式碼和 ​​import "c"​​  語句之間不能有空格。經常會出現找不到 C 函數等等問題。

​總得來說,日常 Go 開發還是不需要此類高階用法,也就是說其實我們平常程式設計過程中不太需要 cgo,大多數情況下還是儘量用 Go 語言自己實現。如果確實需要使用 C 語言,還是得多去了解 ​ ​cgo​​ 的檔案,以防出錯。

到此這篇關於Go 語言中執行 C程式 程式碼 的文章就介紹到這了,更多相關Go中執行 C 程式碼 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com