我已经完成了在游戏内运行盒子的代码。它被称为猜正确的数字!这意味着您可以选择一个介于0到10之间的数字,如果该数字不正确,则会显示消息,请您重试;否则,将显示一条消息,表明您是胜利者,可以选择退出或重新启动。当我尝试使用gcc
进行编译时,好像我需要创建一个makefile
,但是我从未做过为单个文件创建makefile或调用第二个文件的情况。 answer
?
到目前为止,我已经从事C编程四个月了。我的程序名称是game.c
,用于创建Game
(./Game
)以启动程序(游戏)。如何为此编写一个makefile?
我不知道什么是“诅咒”,所以到目前为止,当我进行大量研究时,我想自己学习如何使用诅咒(<ncurses.h>
),但我看不出诅咒和ncurses。在下面使用gcc
后,我创建了编译错误。
代码段:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <time.h>
// PREDEFINED VALUES FOR DEFINING NON CHANGING VALUES IN CODE THIS CASE
#define WINDOWHEIGHT 20
#define WINDOWWIDTH 60
#define WINDOWSTARTX 0
#define WINDOWSTARTY 0
#define CORRECT 1
#define INCORRECT 0
#define START 2
#define WRONGFORMAT 3
#define MAXVALUE 10//You may change MAXVALUE to any num, i.e. `100` = (0-100).
#define MINVALUE 0
// PREDEFINED VALUES FOR DEFINING NON CHANGING VALUES IN THIS CASE
// initialising global structure for saving amount of right and wrong guesses and number to compare with.
struct game {
int rightGuesses;
int wrongGuesses;
int rightNumber;
} myGame;
void initializeGame()
{
// Returns a pseudo-random integer between 0 and MAXVALUE.
int randomNumber = rand() % MAXVALUE;
myGame.rightGuesses=0;
myGame.rightNumber=randomNumber;
}
WINDOW *create_newwin(int height, int width, int starty, int startx)
{
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win, 0, 0);
wrefresh(local_win);
return local_win;
}
int getGuess()
{
int guess=0;
char guessString[32];
scanf("%s", guessString);
// Read number as string by using scanf, but convert to int for comparison with atoi()
guess= atoi(guessString);
size_t allowedEntries = strspn(guessString, "0123456789");
// Some checking if guess was between allowed range + its a number + checking if answer is correct or not
if(guess>=MINVALUE && guess<=MAXVALUE && guessString[allowedEntries] == '\0')
{
if(guess==myGame.rightNumber)
return CORRECT;
else
return INCORRECT;
}
else
return WRONGFORMAT;
}
/**
Function for updating views regarding the input values...
**/
void updateWindowTexts(WINDOW* window, int state)
{
char* greetingsString = "Guess the correct number!";
char* instructionsString = "Enter number 0-10 and press enter";
char* correctGuess = "That was correct! Lets play again";
char* incorrectGuess = "Sorry that was not right";
char* wrongFormat = "incorrect number, please enter number between 0-10";
char* correctAnswersString = "Correct answers:";
char correctAnswers[32];
char wrongAnswers[32];
const char rightAnswersBase[] = "Right numbers so far: ";
sprintf(correctAnswers, "%s%d", rightAnswersBase, myGame.rightGuesses);
const char wrongAnswersBase[] = "Wrong numbers so far: ";
sprintf(wrongAnswers, "%s%d", wrongAnswersBase, myGame.wrongGuesses);
wclear(window);
box (window, 0, 0);
mvwprintw (window, 1, (WINDOWWIDTH/2)-(strlen(greetingsString)/2), greetingsString);
mvwprintw (window, (WINDOWHEIGHT-3), (WINDOWWIDTH/2)-(strlen(correctAnswers)/2), correctAnswers);
mvwprintw (window, (WINDOWHEIGHT-2), (WINDOWWIDTH/2)-(strlen(wrongAnswers)/2), wrongAnswers);
mvwprintw (window, (WINDOWHEIGHT/2), (WINDOWWIDTH/2)-(strlen(instructionsString)/2), instructionsString);
switch (state) {
case START:
break;
case CORRECT:
mvwprintw (window, WINDOWHEIGHT-5, (WINDOWWIDTH/2)-(strlen(correctGuess)/2), correctGuess);
myGame.rightGuesses++;
break;
case INCORRECT:
mvwprintw (window, (WINDOWHEIGHT-5), (WINDOWWIDTH/2)-(strlen(incorrectGuess)/2), incorrectGuess);
myGame.wrongGuesses++;
break;
case WRONGFORMAT:
mvwprintw (window, (WINDOWHEIGHT-5), (WINDOWWIDTH/2)-(strlen(wrongFormat)/2), wrongFormat);
break;
}
wrefresh (window);
}
int main (int argc, char **argv)
{
WINDOW *my_win;
initscr();
// Here we call crea_newwin to make new window, paremeters are static and defined at the top of file
// You can try to play with these numbers
my_win = create_newwin(WINDOWHEIGHT, WINDOWWIDTH, WINDOWSTARTY, WINDOWSTARTX);
// Initialization of random generator, should only be called once.
srand(time(NULL));
initializeGame();
// Update window once before enteringing loop
updateWindowTexts(my_win,START);
while(1)
{
updateWindowTexts(my_win,getGuess());
}
return 0;
}
gcc版本:
/u1/stuff/C/projectFinal> gcc game.c
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `create_newwin':
game.c:(.text+0x73): undefined reference to `newwin'
/usr/bin/ld: game.c:(.text+0xa8): undefined reference to `wborder'
/usr/bin/ld: game.c:(.text+0xb8): undefined reference to `wrefresh'
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `updateWindowTexts':
game.c:(.text+0x251): undefined reference to `wclear'
/usr/bin/ld: game.c:(.text+0x285): undefined reference to `wborder'
/usr/bin/ld: game.c:(.text+0x2c5): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x301): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x33d): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x379): undefined reference to `mvwprintw'
/usr/bin/ld: game.c:(.text+0x3f4): undefined reference to `mvwprintw'
/usr/bin/ld: /tmp/ccOy8YhK.o:game.c:(.text+0x444): more undefined references to `mvwprintw' follow
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `updateWindowTexts':
game.c:(.text+0x4a3): undefined reference to `wrefresh'
/usr/bin/ld: /tmp/ccOy8YhK.o: in function `main':
game.c:(.text+0x4ba): undefined reference to `initscr'
collect2: error: ld returned 1 exit status
答案 0 :(得分:3)
首先,如果您不知道如何手动创建某文件,则无法为其创建文件。因此,让我们首先修复您的编译和链接问题。为了编译您的程序类型:
gcc -c game.c
-c
选项告诉gcc
您只想编译而不是链接。该命令产生一个名为game.o
的目标文件。使用make来使它自动化,您不需要任何东西:make已经知道该怎么做。没有任何Makefile,只需键入:
make game.o CC=gcc
and make会完成任务。请注意,我们通过在命令行中将其标准make变量CC
的值传递给make来告诉要使用的编译器。
接下来,我们要链接项目的所有目标文件(在本例中仅为game.o
,但我们可以有多个,对应于几个不同的源文件)并生成可执行文件。这里要了解的重要一点是,您正在使用的是现有功能的库(ncurses
),默认情况下它不与任何可执行文件链接,因为大多数程序都不使用它。您必须告诉gcc
使用-lncurses
选项将目标文件与此库链接:
gcc game.o -o game -lncurses
请注意,在这样一个非常简单的示例中,您可以
一次调用即可编译并链接到gcc
:
gcc game.c -o game -lncurses
再一次,使已经知道如何执行所有这些操作。由于其他标准的make变量-lncurses
,只需要传递LDLIBS
链接选项即可:
make game CC=gcc LDLIBS=-lncurses
就是这样,您应该可以玩游戏了。如果要自己在真实的Makefile中处理所有详细信息,则应该可以进行以下操作:
game: game.c
gcc game.c -o game -lncurses
但更实用的解决方案是:
CC := gcc
LDLIBS := -lncurses
game: game.c
$(CC) $^ -o $@ $(LDLIBS)
为了理解这一点,您将不得不花一些时间来使用GNU make manual,但这是一个简短而简短的解释。在两个版本中:
<target>: <prerequisite>
<recipe>
告诉他们要构建<target>
,它需要具有<prerequisite>
并运行<recipe>
。它还表明,如果<target>
比<prerequisite>
更新,则无需重新构建<target>
。在上面的第一个版本中,带有:
game: game.c
gcc game.c -o game -lncurses
make知道:
game.c
不存在,则无法建立game
;如果要求这样做,将引发错误game
存在并且比game.c
更新,则无需构建game
如果game
不存在或早于game.c
,则它必须运行:
gcc game.c -o game -lncurses
在第二个版本中:
VARNAME := <value>
是用于将名为VARNAME
的make变量设置为值<value>
的make语法,而$(VARNAME)
是用于获取make变量VARNAME
的值的make语法。 $@
和$^
是两个automatic variables,其值分别是目标和它们出现的配方中规则的所有先决条件的列表。