Go语言调用C语言函数

/*
#include <stdio.h>
 
void say(){
   printf("hello world\n");
}
*/
import "C"
 
func main() {
   /*
   1.C语言的代码都需要利用单行注册或者多行注释注释起来
   2.在C语言代码紧随其后的位置写上import "C"
   3.就可以在go代码中通过C.函数名称 方式来访问C语言的函数
 
   注意点:
   1,C语言代码的注释和import "C"之间不写能任何其他的内容
   2.C语言的代码可以利用多行注释注释起来, 也可以利用单行注释注释起来
    */
    C.say()
}

例如,用Go语言调用C语言的贪吃蛇(贪吃蛇代码来自近期我完成的软件工程专业导论的作业代码)可以实现如下。新创建一个文件夹,里面声明属于包main的文件snake.go

package main;
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <sys/timeb.h>

static struct termios ori_attr, cur_attr;

static __inline 
int tty_reset(void)
{
        if (tcsetattr(STDIN_FILENO, TCSANOW, &ori_attr) != 0)
                return -1;

        return 0;
}


static __inline
int tty_set(void)
{
        
        if ( tcgetattr(STDIN_FILENO, &ori_attr) )
                return -1;
        
        memcpy(&cur_attr, &ori_attr, sizeof(cur_attr) );
        cur_attr.c_lflag &= ~ICANON;
//        cur_attr.c_lflag |= ECHO;
        cur_attr.c_lflag &= ~ECHO;
        cur_attr.c_cc[VMIN] = 1;
        cur_attr.c_cc[VTIME] = 0;

        if (tcsetattr(STDIN_FILENO, TCSANOW, &cur_attr) != 0)
                return -1;

        return 0;
}

static __inline
int kbhit(void) 
{
                   
        fd_set rfds;
        struct timeval tv;
        int retval;

        // Watch stdin (fd 0) to see when it has input. 
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
        // Wait up to five seconds. 
        tv.tv_sec  = 0;
        tv.tv_usec = 0;

        retval = select(1, &rfds, NULL, NULL, &tv);
        // Don't rely on the value of tv now! 

        if (retval == -1) {
                perror("select()");
                return 0;
        } else if (retval)
                return 1;
        // FD_ISSET(0, &rfds) will be true. 
        else
                return 0;
        return 0;
}

// long long getSystemTime(){
	// struct timeb t;
	// ftime(&t);
	// return 1000ll * t.time + t.millitm;
// }

//将你的 snake 代码放在这里

#define SNAKE_MAX_LENGTH 100 //贪吃蛇的最大长度
#define SNAKE_HEAD 'H' //贪吃蛇头部的字符标记
#define SNAKE_BODY 'X' //贪吃蛇身体的字符标记
#define BLANK_CELL ' ' //地图上空地的字符标记
#define SNAKE_FOOD '$' //地图上食物的字符标记
#define WALL_CELL '*' //地图上墙壁/障碍的字符标记
#define MAP_HEIGHT 12 //地图高度
#define MAP_WIDTH 12 //地图宽度
#define PRINT_COUNT 75000//循环多少次刷新一次地图
#define MOVE_TIME (CLOCKS_PER_SEC*6/10)//移动的时间间隔(毫秒)
#define EXTRA_MOVE (MOVE_TIME/6)//立即(连续)切换方向时获得的速度增益

char gameMap[MAP_HEIGHT + 1][MAP_WIDTH + 1]=//预定义的地图
	{"************",
	 "*XXXXH     *",
	 "*     ***  *",
	 "*          *",
	 "*   *      *",
	 "*   *      *",
	 "*   *      *",
	 "*       *  *",
	 "*       *  *",
	 "*       *  *",
	 "*          *",
	 "************"};

char START_DIRECTION = 'D';

int snakeX[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};//蛇占据的位置X坐标 从0开始增大表示蛇头到蛇尾
int snakeY[SNAKE_MAX_LENGTH] = {5, 4, 3, 2, 1};//蛇占据的位置Y坐标 从0开始增大表示蛇头到蛇尾
int snake_length = 5;//蛇的长度
int headX = 1;//蛇头X坐标
int headY = 5;//蛇头Y坐标
int eat, score = 0;//eat表示蛇是否吃到了食物 score表示当前游戏得分

void printMap(){//输出游戏界面
	printf("\033[2J");//清空屏幕
	printf("\033[1;1H");
	printf("pressed `q` to quit!\n");
	int i, j;
	for(i = 0; i < MAP_HEIGHT; ++i){//逐行输出地图
		for(j = 0; j < MAP_WIDTH; ++j){//每一行逐个字符输出地图
			if (gameMap[i][j] == SNAKE_HEAD || gameMap[i][j] == SNAKE_BODY)
				printf("\033[42;34m%c\033[0m", gameMap[i][j]);
			else if (gameMap[i][j] == SNAKE_FOOD)
				printf("\033[43;31m%c\033[0m", gameMap[i][j]);
			else
				putchar(gameMap[i][j]);
		}
		putchar('\n');
	}
	printf("Score: %d\n", score);//输出分数
}

void get_move(char ch, int *dx, int *dy){//根据ch字符获得X,Y坐标对应的方向增量
	switch (ch){
		case 'w': case 'W'://向上
			*dx = -1;
			*dy = 0;
			break;
		case 'a': case 'A'://向左
			*dx = 0;
			*dy = -1;
			break;
		case 's': case 'S'://向下
			*dx = 1;
			*dy = 0;
			break;
		case 'd': case 'D'://向右
			*dx = 0;
			*dy = 1;
			break;
		default://其他方向无效 
			*dx = 0;
			*dy = 0;
			break;
	}
}

void updateGameMap(){//更新游戏地图
	if (!eat)//没有增长蛇的身体
		gameMap[snakeX[snake_length - 1]][snakeY[snake_length - 1]] = BLANK_CELL;//蛇身体最后一个格子要变为空格(因为离开了格子且蛇没有增长) 否则不用变为空格
	gameMap[snakeX[0]][snakeY[0]] = SNAKE_BODY;//之前的蛇头所在格子变为蛇的身体所在格子
	gameMap[headX][headY] = SNAKE_HEAD;//新移动到的格子字符变为蛇头标记
}

void updateSnake(){//更新蛇身体占据位置的数组
	if (eat)//吃到了 增加身体长度
		++snake_length;
	int i;
	for(i = snake_length - 1; i; --i){//每一个位置的坐标更新为移动之前的蛇身体上一个位置坐标
		snakeX[i] = snakeX[i - 1];
		snakeY[i] = snakeY[i - 1];
	}
	snakeX[0] = headX;//蛇头坐标更新为新移动到的格子坐标
	snakeY[0] = headY;
}

void snakeMoveTo(const int dx, const int dy){//蛇移动到相邻的(dx, dy)坐标
	headX = dx;//更新头部坐标
	headY = dy;
	updateGameMap(); //更新地图
	updateSnake();//更新蛇身体占据位置的坐标
}

void putFood(){//放置食物
	int x, y;
	while (1){ 
		x = rand() % MAP_HEIGHT;//随机选择一个X
		y = rand() % MAP_WIDTH;//随机选择一个Y
		if (gameMap[x][y] == BLANK_CELL){//是空地
			gameMap[x][y] = SNAKE_FOOD;//变成食物
			break;//成功放置 退出
		}
	}
}

char str[50];//读入的用户输入缓冲区

int snake(){
	//设置终端进入非缓冲状态
	int tty_set_flag;
	tty_set_flag = tty_set();

	int dx, dy, nx, ny, newdx, newdy;
	get_move(START_DIRECTION, &dx, &dy);//获得X坐标,Y坐标增量

	//将你的 snake 代码放在这里
	srand(time(NULL));//随机种子初始化
	putFood();//放置一个食物	
	int count = 0;
	// long long lasTime = getSystemTime(), nowTime;
	clock_t lasTime = clock(), nowTime;
	printMap();//输出地图	
	while(1) {
		++count;
		if (count == PRINT_COUNT){
			printMap();//输出地图	
			count = 0;
		}			
		if(kbhit()) {
			const int key = getchar();
			// printf("%c pressed\n", key);
			if(key == 'q') 
				break;
			get_move(key, &newdx, &newdy);//获得X坐标,Y坐标增量
			if ((newdx || newdy) && !(newdx == -dx && newdy == -dy)){//如果方向不是蛇上一次移动的反方向 且为有效的移动方向 则更新方向
				dx = newdx;
				dy = newdy;
				lasTime -= EXTRA_MOVE;				
			}
		}else{
			// fprintf(stderr, "<no key detected>\n");
		}
		nowTime = clock();//getSystemTime();
		if (nowTime >= lasTime + MOVE_TIME){
			nx = dx + headX;//更新按当前步走之后到达的位置坐标
			ny = dy + headY;
			if (gameMap[nx][ny] == WALL_CELL || gameMap[nx][ny] == SNAKE_BODY)//为墙壁 或者 蛇的身体 游戏结束
				break;
			eat = 0;//先标记为没有吃到
			if (gameMap[nx][ny] == SNAKE_FOOD){//是食物
				if (snake_length < SNAKE_MAX_LENGTH)//如果没有超过蛇允许的最大长度
					eat = 1;//蛇变长
				++score;//分数增加
			}
			snakeMoveTo(nx, ny);//移动
			if (eat)//吃掉了食物
				putFood();//需要重新放置食物
			lasTime = nowTime;
		}
	}
	printf("Game Over!!!\n");//输出失败信息

	//恢复终端设置
	if(tty_set_flag == 0) 
		tty_reset();

	return 0;
}
*/
import "C"

func main() {
	C.snake()
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到,对于复杂的C语言代码(包含很多函数,全局变量,以及许多引用的头文件与宏定义,条件编译等代码与语法特性),Go语言均可以兼容并可以方便地调用内嵌C函数,运行结果也没有出现问题。Go语言对于调用内嵌C函数提供了健壮稳定的支持。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值