从 C 调用的 Go 中的整数除法
integer division in Go called from C
我可以通过这个程序在 go 中执行整数除法:
package main
import "fmt"
func main() {
a := 10
b := 5
fmt.Println(a/b)
}
然后我用go写了一个程序,里面有+、-、*和/的函数。
我用 C 语言编写了一个程序,它调用每个函数并执行算术运算。
除除法外,代码工作正常。
带有函数的go文件是:(calc.go)
package main
func Add(a, b int) int {
return a + b
}
func Sub(a, b int) int {
return a - b
}
func Mul(a, b int) int {
return a * b
}
func Div(a, b int) int {
return a / b
}
调用这些函数的C程序是:(calcc.c)
#include <stdio.h>
extern int go_add(int, int) __asm__ ("main.Add");
extern int go_sub(int, int) __asm__ ("main.Sub");
extern int go_mul(int, int) __asm__ ("main.Mul");
extern int go_div(int, int) __asm__ ("main.Div");
int menu()
{
int op;
printf("\n1 add");
printf("\n2 sub");
printf("\n3 mul");
printf("\n4 div");
printf("\nEnter your choice : ");
scanf("%d", &op);
return op;
}
int main() {
int op, ch, result, a, b;
do{
op= menu();
printf("First number : ");
scanf("%d", &a);
printf("Second number : ");
scanf("%d", &b);
switch(op)
{
case 1:
result = go_add(a, b);
printf("Result : %d" , result);
break;
case 2:
result = go_sub(a, b);
printf("Result : %d" , result);
break;
case 3:
result = go_mul(a, b);
printf("Result : %d" , result);
break;
case 4:
result = go_div(a, b);
printf("Result : %d" , result);
break;
default:
printf("Invalid choice ! ");
}
printf("\nAnother operation? (1 if yes) : ");
scanf("%d", &ch);
} while(ch==1);
printf("\nThank you!");
}
我使用以下命令在终端上编译:
gccgo -c calc.go
- 和
gcc calc.o calcc.c -o main
并收到此错误:
对“__go_runtime_error”的未定义引用
collect2:错误:ld 返回了 1 个退出状态
我应该如何解决这个问题?
您需要 link 使用 gccgo
而不是正常 gcc
。正常的 gcc 不知道它应该 link 针对 go 运行时 (libgo)。
根据您的配置,您可能还需要指定可以找到运行时库的位置。例如,通过静态嵌入它或使其在 LD_LIBRARY_PATH
环境变量中可用。
示例:
gccgo -static-libgo calc.o calcc.o -o main
有关详细信息,请查看 Setting up and using gccgo。
我相信您使用 __asm__
的方法是特定于 gccgo 的(我以前从未见过)。
standard way 将 Go 函数导出到 C 是通过 Go 代码中的“//export name
”注释。
此外,通过 cgo 的标准 Go<->C 要求将 C 代码链接到 Go 和 Go 的主要运行中,而不是相反。这样 Go 运行时就完全 运行。否则 goroutines、垃圾收集器等就不会是 运行。当然,Go 的 main 可能只是对 C 伪主函数的简单调用,该函数完成所有工作并仅在需要时回调到 Go。
鉴于这些要点,您尝试使用 standard cgo 并完全 go build
-able 的一个小例子是:
calc.go:
package main
// /* could be in a declared in a header file instead */
// extern void pseudo_main(void);
import "C"
//export Add
func Add(a, b int) int {
return a + b
}
// … etc …
//export Div
func Div(a, b int) int {
return a / b
}
// Main needs to be Go so that the go runtime
// gets started so you can use goroutines, the
// garbage collector, etc,etc.
//
// It can just be a trivial call into a C main like
// function.
func main() {
C.pseudo_main()
}
和calc.c:
#include <stdio.h>
#include "_cgo_export.h" // file auto-generated by cgo from Go's "//export func" comments
// passing argc, argv, envp like arguments
// if desired is left as an excersise :)
void pseudo_main(void) {
int x, y, z;
printf("Hello from C\n");
x = 42;
y = 6;
z = Add(x, y);
printf("%d + %d = %d\n", x, y, z);
z = Div(x, y);
printf("%d / %d = %d\n", x, y, z);
}
构建和运行(在类似 Unix 的主机上):
% go build -o calc
% ./calc
注意:通常您不会使用 -o
,您会让工具根据包或目录名称选择名称。我在这里使用了 -o
来列出 精确的 和可重复的命令,但没有指定文件所在的目录。进一步注意,对于 Microsoft Windows 它会有所不同。此外,如果您对 cgo 幕后发生的事情感兴趣,请尝试 go build -x
.
输出:
Hello from C
42 + 6 = 48
42 / 6 = 7
我可以通过这个程序在 go 中执行整数除法:
package main
import "fmt"
func main() {
a := 10
b := 5
fmt.Println(a/b)
}
然后我用go写了一个程序,里面有+、-、*和/的函数。 我用 C 语言编写了一个程序,它调用每个函数并执行算术运算。 除除法外,代码工作正常。
带有函数的go文件是:(calc.go)
package main
func Add(a, b int) int {
return a + b
}
func Sub(a, b int) int {
return a - b
}
func Mul(a, b int) int {
return a * b
}
func Div(a, b int) int {
return a / b
}
调用这些函数的C程序是:(calcc.c)
#include <stdio.h>
extern int go_add(int, int) __asm__ ("main.Add");
extern int go_sub(int, int) __asm__ ("main.Sub");
extern int go_mul(int, int) __asm__ ("main.Mul");
extern int go_div(int, int) __asm__ ("main.Div");
int menu()
{
int op;
printf("\n1 add");
printf("\n2 sub");
printf("\n3 mul");
printf("\n4 div");
printf("\nEnter your choice : ");
scanf("%d", &op);
return op;
}
int main() {
int op, ch, result, a, b;
do{
op= menu();
printf("First number : ");
scanf("%d", &a);
printf("Second number : ");
scanf("%d", &b);
switch(op)
{
case 1:
result = go_add(a, b);
printf("Result : %d" , result);
break;
case 2:
result = go_sub(a, b);
printf("Result : %d" , result);
break;
case 3:
result = go_mul(a, b);
printf("Result : %d" , result);
break;
case 4:
result = go_div(a, b);
printf("Result : %d" , result);
break;
default:
printf("Invalid choice ! ");
}
printf("\nAnother operation? (1 if yes) : ");
scanf("%d", &ch);
} while(ch==1);
printf("\nThank you!");
}
我使用以下命令在终端上编译:
gccgo -c calc.go
- 和
gcc calc.o calcc.c -o main
并收到此错误: 对“__go_runtime_error”的未定义引用 collect2:错误:ld 返回了 1 个退出状态
我应该如何解决这个问题?
您需要 link 使用 gccgo
而不是正常 gcc
。正常的 gcc 不知道它应该 link 针对 go 运行时 (libgo)。
根据您的配置,您可能还需要指定可以找到运行时库的位置。例如,通过静态嵌入它或使其在 LD_LIBRARY_PATH
环境变量中可用。
示例:
gccgo -static-libgo calc.o calcc.o -o main
有关详细信息,请查看 Setting up and using gccgo。
我相信您使用 __asm__
的方法是特定于 gccgo 的(我以前从未见过)。
standard way 将 Go 函数导出到 C 是通过 Go 代码中的“//export name
”注释。
此外,通过 cgo 的标准 Go<->C 要求将 C 代码链接到 Go 和 Go 的主要运行中,而不是相反。这样 Go 运行时就完全 运行。否则 goroutines、垃圾收集器等就不会是 运行。当然,Go 的 main 可能只是对 C 伪主函数的简单调用,该函数完成所有工作并仅在需要时回调到 Go。
鉴于这些要点,您尝试使用 standard cgo 并完全 go build
-able 的一个小例子是:
calc.go:
package main
// /* could be in a declared in a header file instead */
// extern void pseudo_main(void);
import "C"
//export Add
func Add(a, b int) int {
return a + b
}
// … etc …
//export Div
func Div(a, b int) int {
return a / b
}
// Main needs to be Go so that the go runtime
// gets started so you can use goroutines, the
// garbage collector, etc,etc.
//
// It can just be a trivial call into a C main like
// function.
func main() {
C.pseudo_main()
}
和calc.c:
#include <stdio.h>
#include "_cgo_export.h" // file auto-generated by cgo from Go's "//export func" comments
// passing argc, argv, envp like arguments
// if desired is left as an excersise :)
void pseudo_main(void) {
int x, y, z;
printf("Hello from C\n");
x = 42;
y = 6;
z = Add(x, y);
printf("%d + %d = %d\n", x, y, z);
z = Div(x, y);
printf("%d / %d = %d\n", x, y, z);
}
构建和运行(在类似 Unix 的主机上):
% go build -o calc
% ./calc
注意:通常您不会使用 -o
,您会让工具根据包或目录名称选择名称。我在这里使用了 -o
来列出 精确的 和可重复的命令,但没有指定文件所在的目录。进一步注意,对于 Microsoft Windows 它会有所不同。此外,如果您对 cgo 幕后发生的事情感兴趣,请尝试 go build -x
.
输出:
Hello from C
42 + 6 = 48
42 / 6 = 7