簡體   English   中英

如何在C語言中為“猜對了數字!”游戲編寫“ Makefile”?

[英]How to write a “Makefile” for a “Guess the Right Number!” game in C?

我已經完成了在游戲內運行盒子的代碼。 它被稱為猜正確的數字! 這意味着您可以選擇一個介於0到10之間的數字,如果該數字不正確,則會顯示消息,請您重試;否則,將顯示一條消息,表明您是勝利者,可以選擇退出或重新啟動。 當我嘗試使用gcc進行編譯時,看起來好像我需要創建一個makefile ,但我從未做過為單個文件或另一個文件創建makefile的answer

到目前為止,我已經從事C編程四個月了。 我的程序名稱是game.c用於創建Game./Game Game )以啟動程序(游戲)。 如何為此編寫一個makefile?

我不知道什么是“詛咒”,所以到目前為止,當我進行大量研究時,我想自己學習如何使用curses( <ncurses.h> ),但我看不到curses和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

首先,如果您不知道如何手動創建某文件,則無法為該文件創建Makefile。 因此,讓我們首先修復您的編譯和鏈接問題。 為了編譯您的程序類型:

gcc -c game.c

-c選項告訴gcc您只想編譯而不是鏈接。 該命令生成一個名為game.o的目標文件。 使用make來使它自動化,您不需要任何東西:make已經知道該怎么做。 沒有任何Makefile,只需鍵入:

make game.o CC=gcc

並且make會勝任。 請注意,我們通過在命令行中將其標准make變量CC的值傳遞給make來告訴make使用哪個編譯器。

接下來,我們要鏈接項目的所有目標文件(在本例中僅是game.o ,但我們可以有多個,對應於幾個不同的源文件)並生成可執行文件。 在這里要了解的重要一點是,您正在使用的是已經存在的函數庫( ncurses ),該函數庫默認情況下不與任何可執行文件鏈接,因為大多數程序都不使用它。 您必須告訴gcc使用-lncurses選項將目標文件與此庫鏈接:

gcc game.o -o game -lncurses

請注意,在這樣一個非常簡單的示例中,您可以在一次調用中編譯並鏈接到gcc

gcc game.c -o game -lncurses

再說一遍,已經知道如何做所有這一切。 由於其他標准的make變量LDLIBS ,只需要傳遞-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手冊,但是這里只是一個簡短的解釋。 在兩個版本中:

<target>: <prerequisite>
    <recipe>

告訴make要構建<target>它需要具有<prerequisite>並運行<recipe> 它還告訴我們,如果<target><prerequisite>更新,則無需重新構建<target> 在上面的第一個版本中,具有:

game: game.c
    gcc game.c -o game -lncurses

使知道:

  • 如果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 VARNAME $@$^是兩個自動變量 ,其值分別是目標和出現它們的配方中規則的所有先決條件的列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM