[golang] cgo에서 Go와 C 언어 간의 버퍼 전달

2024. 10. 29. 18:12·Language/Go

서론

Go 언어는 간결하고 효율적인 프로그래밍을 위한 훌륭한 선택이다. 그러나 특정 작업에서는 Pure Go만으로는 한계에 부딪히기도 한다. 특히 미디어 트랜스코딩과 같은 작업에서는 적절한 라이브러리가 없어 C와 같은 저수준 언어의 도움을 받아야 할 때가 있다. 이러한 이유로 나는 Go와 C 간의 상호작용을 구현하기 위해 cgo를 사용하여 버퍼를 전달하는 작업을 했었다. 이 글에서는 cgo를 사용하여 Go와 C 간의 버퍼를 전달하는 방법을 간략하게 정리해본다.

 

Go에서 사용하던 버퍼를 C로 전달

package main

// #include <stdio.h>
//
// void Go2C(unsigned char* buf, int len) {
//     for (int i=0; i<len; i++)
//         printf("%02X ", buf[i]);
//     printf("\n");
// }
import "C"

func main() {
	goBuf := []byte("Jae-Sung\x00")
	C.Go2C((*C.uchar)(&goBuf[0]), C.int(len(goBuf)))
}

출력 결과

4A 61 65 2D 53 75 6E 67 00

Go에서는 버퍼의 크기를 따로 관리하지 않아도 내장 함수 len을 통해서 사용할 수 있지만 C에서는 메모리 주소만 가지고 크기를 알기 어려워 주소와 길이를 따로 전달해야 한다.

 

C에서 사용하던 버퍼를 Go로 전달

package main

// #include <stdio.h>
// #include <string.h>
// #include <stdlib.h>
//
// unsigned char* C2Go(int* len) {
//     if (len) {
//         *len = 9;
//         unsigned char* buf = (unsigned char*)malloc(*len);
//         memcpy(buf, "Jae-Sung\0", *len);
//         return buf;
//     }
//     return NULL;
// }
import "C"
import (
	"fmt"
	"unsafe"
)

func main() {
	var bufLen C.int
	if cbuf := C.C2Go(&bufLen); int(bufLen) > 0 {
		goBuf := make([]byte, int(bufLen))
		copy(goBuf, unsafe.Slice((*byte)(unsafe.Pointer(cbuf)), int(bufLen)))
		C.free(unsafe.Pointer(cbuf))
		for _, v := range goBuf {
			fmt.Printf("%02X ", v)
		}
		fmt.Println()
	}

}

출력 결과

4A 61 65 2D 53 75 6E 67 00

C에서 메모리 주소와 버퍼 크기를 전달 받아서 Go의 []byte 타입으로 복사했다. 아무래도 C의 메모리를 직접적으로 사용하면 recover도 무시하고 프로그램이 죽어버리기 때문에 최대한 조심스럽게 사용한다. C는 가비지 컬렉션이 없기 때문에 Go에서 사용이 끝나면 직접 free를 호출해서 메모리를 해제해야 한다.

'Language > Go' 카테고리의 다른 글

[golang] sync.WaitGroup으로 고루틴 작업 기다리기  (0) 2024.11.09
[golang] html/template 패키지로 동적 페이지 처리하기  (3) 2024.11.07
[golang] json.Marshal에서 HTML 이스케이프 문제  (3) 2024.10.31
[golang] reflect 패키지를 사용한 외부 패키지의 private 필드 접근하기  (0) 2024.10.30
[golang] 동일한 문자열 메모리 공유  (1) 2024.10.28
'Language/Go' 카테고리의 다른 글
  • [golang] html/template 패키지로 동적 페이지 처리하기
  • [golang] json.Marshal에서 HTML 이스케이프 문제
  • [golang] reflect 패키지를 사용한 외부 패키지의 private 필드 접근하기
  • [golang] 동일한 문자열 메모리 공유
在晟
在晟
  • 在晟
    Jae-Sung
    在晟
  • 전체
    오늘
    어제
    • 분류 전체보기 (25)
      • Language (23)
        • Go (23)
      • DBMS (1)
        • MariaDB (1)
      • Notes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Jae-Sung
    • GitHub
  • 인기 글

  • 태그

    filepath
    unsafe
    오블완
    Runtime
    fasthttp
    http
    티스토리챌린지
    go
    recover
    interface{}
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
在晟
[golang] cgo에서 Go와 C 언어 간의 버퍼 전달
상단으로

티스토리툴바