>  기사  >  백엔드 개발  >  경험 공유: golang과 C언어가 어떻게 서로를 부르는지!

경험 공유: golang과 C언어가 어떻게 서로를 부르는지!

藏色散人
藏色散人앞으로
2021-11-25 14:55:354298검색

이 글은 go 언어 튜토리얼 칼럼에서 golang과 C 언어가 어떻게 서로 호출하는지 소개하기 위해 작성되었습니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

go 언어와 c 언어 간의 상호 호출

최근 업무상의 이유로 go 언어와 c 언어 간의 상호 호출 구현이 필요해졌습니다. Go 언어와 C 언어는 불가분하게 연결되어 있기 때문에 둘 사이의 호출은 언어 수준을 통해 실현될 수 있습니다. 아래는 이에 대한 요약입니다.

go 언어 호출 c 언어

다음은 간단한 예입니다.

package main

// #include <stdio.h>
// #include <stdlib.h>
/*
void print(char *str) {
    printf("%s\n", str);
}
*/
import "C"

import "unsafe"

func main() {
    s := "Hello Cgo"
    cs := C.CString(s)
    C.print(cs)
    C.free(unsafe.pointer(cs))
}

"일반적인" go 코드와 비교하여 위 코드에는 몇 가지 "특별한" 사항이 있습니다.

  • 시작 부분의 주석에 나타납니다. c 언어 헤더 파일의 단어

  • c 언어 함수 print는 주석에 정의되어 있습니다

  • C

  • 라는 이름의 "패키지"를 가져옵니다

위에 정의된 c 언어는 기본 함수 Print 함수에서 호출됩니다

우선, 위의 include 헤더 파일 및 인쇄 함수 정의와 마찬가지로 go 소스 파일의 c 언어 코드를 주석으로 묶어야 하며, 두 번째로 import "C" 문이 필요하며 관련이 있습니다. 위의 C 코드는 빈 줄로 구분할 수 없으며 밀접하게 연결되어야 합니다. 여기서 "C"는 패키지 이름이 아니라 네임스페이스와 유사한 개념입니다. 또는 C 언어의 모든 구문 요소는 마지막으로 이 의사 패키지 아래에 있습니다. c 구문 요소는 그 앞에 있어야 합니다. 위 코드에서 C.uint 및 C.print, C.free 등과 같은 의사 패키지 접두사를 추가해야 합니다.

Go에서 C 언어를 호출하는 자세한 사용법은 Go와 C 언어의 상호 운용성을 참조하세요. 이 기사에서는 하나씩 자세히 설명하지 않습니다. #cgo指示符可以指定go源码在编译后与哪些共享库进行链接。例子如下:

// hello.go
package main

// #cgo LDFLAGS: -L ./ -lhello
// #include <stdio.h>
// #include <stdlib.h>
// #include "hello.h"
import "C"

func main() {
    C.hello()
}

// hello.c
#include "hello.h"

void hello()
{
    printf("hello, go\n");
}

// hello.h
extern void hello();

其中在hello.go中,#cgo指示符后面添加LDFLAGS: -L ./ -lhello,作用是在go代码编译时,指定在当前目录查找so库并进行链接。

因此,只需要把hello.c编译成动态库,再编译go代码,即可在运行go代码的时候调用共享库中的c语言函数。指令如下:

  • gcc -fPIC -o libhello.so hello.c

  • go build -o hello

  • ./hello

c语言调用go语言

与在go中调用c源码相比,在c中使用go函数的场合较少。因为一般来说,采用高级语言作为粘合剂调用低级语言能充分发挥各自的特点,而用低级语言调用高级语言反而有可能降低低级语言的性能优势,在go中,可以使用”export + 函数名“来导出go函数为c代码所用,看一个简单的例子:

// hello.go
package main

import "C"

import "fmt"

// export Go2C
func Go2C() {
    fmt.Println("hello, C")
}

可通过go build的编译选项,将go代码编译成共享库以供c代码调用。注意,编译so库时必须存在main及main函数(即使main函数为空)。编译指令如下:go build -v -x -buildmode=c-shared -o libhello.so hello.go

编译成功后,只需在c代码中引入新生成的头文件及编译时链接动态库即可实现go函数的调用。代码如下:

// hello.c
#include <stdio.h>
#include "libhello.h"

int main()
{
    Go2C();
    return 0;
}

通过gcc -o hello -L. -lhello,即可编译成可执行程序。注意,运行前必须确定共享库运行时查找路径中存在需要链接的共享库,可通过将so库路径放到/usr/lib或者修改环境变量LD_LIBRARY_PATH。

小结

go语言可以通过内嵌c代码的形式调用c语言,也可以通过调用共享库函数的方式实现;至于c语言调用go函数,则可以通过go build

위의 예에서는 Go 코드에 C 언어가 포함되어 있습니다. 코드가 더 크고 복잡하다면 이는 분명히 매우 비전문적입니다. 그렇다면 C 언어 코드를 Go 코드와 분리하여 별도로 정의할 수 있을까요? 대답은 '예'입니다. 공유 라이브러리를 통해 달성할 수 있습니다.
🎜cgo는 컴파일 후 Go 소스 코드가 링크될 공유 라이브러리를 지정하기 위해 #cgo 지시어를 제공합니다. 예제는 다음과 같습니다. 🎜rrreee🎜hello.go에서 go 코드를 컴파일할 때 사용되는 #cgo 표시 뒤에 LDFLAGS: -L ./ -lhello를 추가합니다. . 현재 디렉토리에서 so 라이브러리를 검색하여 링크하도록 지정합니다. 🎜🎜 따라서 hello.c를 동적 라이브러리로 컴파일한 후 go 코드만 컴파일하면 되고, go 코드 실행 시 공유 라이브러리에 있는 c 언어 함수를 호출하면 됩니다. 지침은 다음과 같습니다. 🎜🎜🎜🎜gcc -fPIC -o libhello.so hello.c🎜🎜🎜🎜go build -o hello🎜🎜🎜🎜./ hello🎜🎜🎜🎜c 언어 호출 go 언어🎜🎜go에서 c 소스 코드를 호출하는 것과 비교하면 c에서 go 함수를 사용하는 경우가 적습니다. 왜냐하면 일반적으로 고급 언어를 접착제로 사용하여 저급 언어를 호출하면 각각의 특성을 최대한 발휘할 수 있는 반면, 저급 언어를 사용하여 고급 언어를 호출하면 Go에서는 "내보내기 + 함수 이름"을 사용할 수 있습니다. "C 코드에서 사용할 Go 함수를 내보내려면 간단한 예를 살펴보세요. 🎜rrreee🎜 의 컴파일 옵션을 사용할 수 있습니다. go build는 go 코드를 c 코드 호출을 위한 공유 라이브러리로 컴파일합니다. so 라이브러리를 컴파일할 때 메인 및 메인 함수가 존재해야 한다는 점에 유의하세요(메인 함수가 비어 있더라도). 컴파일 지침은 다음과 같습니다: go build -v -x -buildmode=c-shared -o libhello.so hello.go. 🎜🎜성공적인 컴파일 후에는 새로 생성된 헤더 파일을 C 코드에 도입하고 컴파일 중에 동적 라이브러리를 링크하기만 하면 go 함수 호출을 실현할 수 있습니다. 코드는 다음과 같습니다. 🎜rrreee🎜gcc -o hello -L -lhello를 사용하여 실행 가능한 프로그램으로 컴파일합니다. 실행하기 전에 링크해야 할 공유 라이브러리가 공유 라이브러리 런타임 검색 경로에 있는지 확인해야 합니다. so 라이브러리 경로를 /usr/lib에 넣거나 환경 변수 LD_LIBRARY_PATH를 수정할 수 있습니다. 🎜🎜요약🎜🎜go 언어는 c 코드를 삽입하거나 공유 라이브러리 함수를 호출하여 c 언어를 호출할 수 있습니다. c 언어 호출 go 함수의 경우 go 빌드를 사용하여 Go 코드를 a로 컴파일할 수 있습니다. C 코드에서 사용하기 위한 공유 라이브러리입니다. 이 글의 공유 라이브러리는 모두 동적 공유 라이브러리라는 점에 유의하세요. 정적 공유 라이브러리는 테스트되지 않았습니다. 관심 있는 분들은 구현해 보세요. 🎜🎜

위 내용은 경험 공유: golang과 C언어가 어떻게 서로를 부르는지!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제