英文:
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
然后出现了以下错误:
undefined reference to `__go_runtime_error'
collect2: error: ld returned 1 exit status
你应该如何解决这个问题?
英文:
I am able to perform integer division in go by this program :
package main
import "fmt"
func main() {
a := 10
b := 5
fmt.Println(a/b)
}
Then I made a program in go that has functions for +, -, * and /.
and I made a program in C that calls each of these functions and performs arithmetic operations.
Except division, the code works fine.
The go file with the functions is : (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
}
And the C program that calls these functions is : (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!");
}
I compiled on the terminal using the commands :
>gccgo -c calc.go
- and
>gcc calc.o calcc.c -o main
And got this error :
undefined reference to `__go_runtime_error'
collect2: error: ld returned 1 exit status
How should I fix this?
答案1
得分: 1
你需要使用gccgo
而不是普通的gcc
进行链接。普通的gcc不知道它应该链接到Go运行时库(libgo)。
根据你的配置,你可能还需要指定运行时库的位置。例如,通过静态嵌入或将其放在LD_LIBRARY_PATH
环境变量中可用。
示例:
gccgo -static-libgo calc.o calcc.o -o main
更多信息,请参阅设置和使用gccgo。
英文:
You need to link using gccgo
and not with normal gcc
. Normal gcc doesn't know that it ought to link against the go runtime (libgo).
Depending on your configuration, you might also need to specify where the runtime library can be found. For example by embedding it statically or by making it available in the LD_LIBRARY_PATH
environment variable.
Example:
gccgo -static-libgo calc.o calcc.o -o main
For more information, check Setting up and using gccgo.
答案2
得分: 1
我相信你使用__asm__
的方法是特定于gccgo的(我以前从未见过)。
将Go函数导出到C的标准方法是通过在Go代码中使用"//export name
"注释。
此外,通过cgo进行标准的Go<->C交互需要将C代码链接到Go中,并且Go的主函数运行,而不是相反。这样可以确保Go运行时完全运行。否则,goroutine、垃圾回收器等将无法运行。当然,Go的主函数可以只是一个简单的调用C伪主函数的函数,该函数完成所有工作,并根据需要回调到Go中。
根据这些要点,下面是一个使用标准的cgo和完全可go build
的小例子:
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
英文:
I believe your method of using __asm__
is gccgo specific (I've never seen it before).
The standard way to export Go functions to C is via an "//export name
" comment in the Go code.
Further, standard Go<->C via cgo requires that C code is linked into Go and Go's main runs and not the other way around. This is so that the Go runtime is fully running. Otherwise goroutines, the garbage collector, etc would not be running. Of course Go's main could just be a simple call to a C pseudo-main function that does all the work and calls back into Go only as needed.
Given these points a small example of what you tried using standard cgo and fully go build
-able is this:
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()
}
and 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);
}
building and running (on a Unix like host):
% go build -o calc
% ./calc
<sub>Note: normally you wouldn't use -o
, you'd let the tool pick the name based on package or directory name. I've used -o
here to list exact and repeatable commands without specifying what directory the files are in. Further note, for Microsoft Windows it would be different. Also, if you're interested in what goes on behind the scenes with cgo, try go build -x
.</sub>
output:
Hello from C
42 + 6 = 48
42 / 6 = 7
See also: The Go Blog: C? Go? Cgo!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论