结构的多重定义错误,但我没有在任何地方看到错误(C++)
Error multiple definition of struct, but i dont see the error anywhere ( C++ )
制作了一个结构,编译了我的程序,运行完美,没有改变任何东西,关闭了 vm,重新启动了 vm 和 vsc,然后再次在控制台中制作并出现了这个错误
1 warning generated.
linking build/main.o
build/Game.o:(.bss+0x60): multiple definition of `scoreArray'
build/main.o:(.bss+0x10): first defined here
clang-5.0: error: linker command failed with exit code 1 (use -v to see
invocation)
Makefile:33: recipe for target 'build/2048' failed
make: *** [build/2048] Error 1
这是我的代码,我看不到任何重新定义它的东西,请有人帮我找到它,
这是它在
中使用的头文件和源文件
main.cpp
/**
* File: main.cpp
* Author: not lettin u know :)
* Date: 20-11-2019
* Desc:
* Copyright: University of West of England 2017
*/
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
// include the UFCFGL301's standard library
#include <ufcfgl-30-1.h>
#include <iostream>
#include <time.h>
#include "Grid.h"
#include "Game.h"
// uncomment if you want to use the graphics library
#include <graphics.h>
using namespace std;
using namespace uwe;
/**
* main routine, implements ...
* @return success
*/
int main(void) {
srand(time(0));
Game game;
// -------Initialising Game-------
while(1){
game.chooseFunction();
grid.totalScore = 0;
grid.initGrid();
grid.addValue();
cout << "3[2J"; // this clears the terminal
cout << "\nPlayer Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves << "\n\nlast input = N/A \n";
grid.setScore(grid.score);
grid.drawGrid();
// This launches graphics window where all keypresses are inputted
// this is also where we start the lambda functions in a loop
initialiseGraphics(600,400);
loop (
[&](){
},
[&](keyPress keyPress){
// w a s d are also inputted into an integer as their respective ascii value
// so this allows the use of w a s d and also the arrow keys in controlling
// the moves of the player
int kpVal = keyPress.getKeyCode();
if ( kpVal == 'q' ){
return true;
}
if ( kpVal == 'w' || kpVal == keyPress::upKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftUp();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = UP \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 'a' || kpVal == keyPress::leftKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftLeft();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = LEFT \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 's' || kpVal == keyPress::downKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftDown();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = DOWN \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 'd' || kpVal == keyPress::rightKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftRight();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = RIGHT \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
return false;
}
);
}
}
Game.h
#pragma once
#include <cstdio>
#include <string>
#include <graphics.h>
#include "Grid.h"
class Game{
public:
bool canMove();
bool checkWin();
bool checkLoss();
void checkGameState();
void chooseFunction();
void printHighScores();
void writeHighScore();
bool gameFinished = false;
private:
};
extern Game game;
struct highScore {
int score;
std::string name;
};
Game.cpp
#include "Grid.h"
#include "Game.h"
#include <sstream>
#include <unistd.h>
#include <iostream>
#include <cstdio>
#include <graphics.h>
#include <fstream>
#include <string>
#include <algorithm> //std::sort for array of structs sorting based on struct
// integer
Grid grid;
highScore scoreArray[100];
// functions to check game state for win or loss or can make moves
bool Game::canMove(){
bool canMove = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; y++){
if (grid.grid[x][y] == Grid::emptyCell) {
canMove = true;
return canMove;
}
// multiple if statements due to if grid[3][1] was being checked with
// grid[3+1][1] then it would loop around and check against grid[1][2]
// for an unknown reason, so to combat this i had to check specifically against
// the edge of the board
else if(y == 3 && x < 3){
if( grid.grid[x][y] == grid.grid[x+1][y] ){
canMove = true;
return canMove;
}
}
else if(x == 3 && y < 3){
if( grid.grid[x][y] == grid.grid[x][y+1] ){
canMove = true;
return canMove;
}
}
else if( ( x < 3 && y < 3 ) &&
(grid.grid[x][y] == grid.grid[x][y+1] ||
grid.grid[x][y] == grid.grid[x+1][y]) ) {
canMove = true;
return canMove;
}
}
}
return canMove;
}
bool Game::checkWin(){
bool win = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; y++){
if(grid.grid[x][y] == 2048){
win = true;
return win;
}
}
}
return win;
}
bool Game::checkLoss(){
bool loss = false;
if(canMove() == false ){
loss = true;
return loss;
}
return loss;
}
void Game::checkGameState(){
if(checkWin() == true) {
std::cout << "\n\n--------YOU WIN--------\n\n";
gameFinished = true;
writeHighScore();
}
else if(checkLoss() == true) {
std::cout << "\n\n--------YOU LOSE--------\n\n";
gameFinished = true;
}
}
// functions for initializing game/options
void Game::chooseFunction(){
while(1){
int function = 0;
std::cout << "\nPlease Choose A Function\n1) Play Game\n2) High Scores"
<< "\n3) Exit Program";
std::cout << "\nFunction : ";
std::cin >> function;
if (std::cin.fail() || function < 1 || function > 3) {
std::cin.clear();
std::cin.ignore(1000,'\n'); // this is to stop the validation from
// looping for each wrong character entered
std::cout << "Not a valid option, Please re-enter \n\n" ;
sleep(1);
}
else if (function == 1) {
std::cout << "------Launching Game------\n\n";
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
return ;
}
else if (function == 2) {
std::cout << "---Printing High Scores---\n";
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
printHighScores();
sleep(10);
}
else if (function == 3) {
std::cout << "-------Now Exiting------- \n\n" << std::flush ;
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
exit(0);
}
}
}
// This function is called upon a win, and writes the high score ,of those who
// win the game, into a text file under the format of SCORE - NAME
void Game::writeHighScore(){
std::string name;
std::cout << "\nEnter Name To Store High Score ( Max 16 Characters )\n"
<< "Name : ";
std::getline(std::cin,name);
// this is to stop the string being over 16 characters
if(std::cin.fail() || name.length() > 16){
std::cout << "\n\nPlease Enter A Max of 16 Characters\n\n";
writeHighScore();
return;
}
else{
// This opens the output stream to the high scores text file
// and immediately points to the next free line in the file
std::ofstream HighScore;
HighScore.open ("HighScores.txt", std::ios::app);
HighScore << grid.totalScore << " "<< name << std::endl;
HighScore.close();
return;
}
}
// simple comparator function to be used with std::sort in order to sort
// the array of structs containing scores and their respective player names
bool sortScore(highScore a,highScore b){
return a.score > b.score;
}
// this function prints the high scores from the text file, however
// im not sure how to sort a text file each time its appended, so instead
// when this function is called, it seperates the lines of the files into
// the score and their respective player name, these are stored in a struct
// object for each line, and then the array of structs is sorted using
// std::sort and the comparator function and then the first 10 scores and names
// in the struct array are printed, TLDR, prints Top 10 scores :)
//
// not on the spec for the assignment but i enjoyed learning about how
// i would go about making something like this :)
void Game::printHighScores() { // function to choose and print ascii art
std::ifstream highScores;
highScores.open("HighScores.txt");
std::string line;
int i=0;
if(!highScores){
std::cout << "\nCould Not Open HighScores.txt";
sleep(2);
return;
}
else{
while(getline(highScores, line)){
std::istringstream iss(line);
int score;
std::string name;
// this seperates out the score and the name string from each line in the file
if(!(iss >> score && iss.ignore() && std::getline(iss,name))){
break;
}
// this adds to the array of structs defined in the header file
scoreArray[i].score = score;
scoreArray[i].name = name;
i++;
}
std::sort(&scoreArray[0],&scoreArray[100],sortScore);
}
// and finally... this prints the top 10 scores
std::cout << "\n\n-------HIGH SCORES-------\n\n";
for(int i=0; i<10; i++){
std::cout <<i+1<<") "<<scoreArray[i].score<<" - "<<scoreArray[i].name
<<"\n";
}
}
行
highScore scoreArray[100];
在您的 header 中,只要包含此 header 就声明一个变量。我假设 header 包含在多个源文件中。
将其移至 .cpp
并将其添加 extern
至 header。
基本上,对于包含此 header 的每个源文件,您要声明一个名为 scoreArray
的变量。每个包含此 header 的 .cpp
都将声明其自己的 scoreArray
。链接器在执行链接操作时,会遇到两个同名变量,无法确定哪个变量“正确”,因此它会放弃并生成您所看到的错误。
因此,您需要将定义移动到 .cpp
中,并在 header 中将其作为 extern
引用。 (有几种不同的方法。选择最适合您的方法。)
制作了一个结构,编译了我的程序,运行完美,没有改变任何东西,关闭了 vm,重新启动了 vm 和 vsc,然后再次在控制台中制作并出现了这个错误
1 warning generated.
linking build/main.o
build/Game.o:(.bss+0x60): multiple definition of `scoreArray'
build/main.o:(.bss+0x10): first defined here
clang-5.0: error: linker command failed with exit code 1 (use -v to see
invocation)
Makefile:33: recipe for target 'build/2048' failed
make: *** [build/2048] Error 1
这是我的代码,我看不到任何重新定义它的东西,请有人帮我找到它, 这是它在
中使用的头文件和源文件main.cpp
/**
* File: main.cpp
* Author: not lettin u know :)
* Date: 20-11-2019
* Desc:
* Copyright: University of West of England 2017
*/
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
// include the UFCFGL301's standard library
#include <ufcfgl-30-1.h>
#include <iostream>
#include <time.h>
#include "Grid.h"
#include "Game.h"
// uncomment if you want to use the graphics library
#include <graphics.h>
using namespace std;
using namespace uwe;
/**
* main routine, implements ...
* @return success
*/
int main(void) {
srand(time(0));
Game game;
// -------Initialising Game-------
while(1){
game.chooseFunction();
grid.totalScore = 0;
grid.initGrid();
grid.addValue();
cout << "3[2J"; // this clears the terminal
cout << "\nPlayer Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves << "\n\nlast input = N/A \n";
grid.setScore(grid.score);
grid.drawGrid();
// This launches graphics window where all keypresses are inputted
// this is also where we start the lambda functions in a loop
initialiseGraphics(600,400);
loop (
[&](){
},
[&](keyPress keyPress){
// w a s d are also inputted into an integer as their respective ascii value
// so this allows the use of w a s d and also the arrow keys in controlling
// the moves of the player
int kpVal = keyPress.getKeyCode();
if ( kpVal == 'q' ){
return true;
}
if ( kpVal == 'w' || kpVal == keyPress::upKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftUp();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = UP \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 'a' || kpVal == keyPress::leftKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftLeft();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = LEFT \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 's' || kpVal == keyPress::downKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftDown();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = DOWN \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
if ( kpVal == 'd' || kpVal == keyPress::rightKey ){
cout << "3[2J"; // this clears the terminal
grid.shiftRight();
cout << "Player Score : " << grid.totalScore << "\n";
std::cout << "\nMoves = " << grid.moves
<< "\n\nlast input = RIGHT \n";
grid.setScore(grid.score);
grid.drawGrid();
game.checkGameState();
if(game.gameFinished == true){
return true;
}
}
return false;
}
);
}
}
Game.h
#pragma once
#include <cstdio>
#include <string>
#include <graphics.h>
#include "Grid.h"
class Game{
public:
bool canMove();
bool checkWin();
bool checkLoss();
void checkGameState();
void chooseFunction();
void printHighScores();
void writeHighScore();
bool gameFinished = false;
private:
};
extern Game game;
struct highScore {
int score;
std::string name;
};
Game.cpp
#include "Grid.h"
#include "Game.h"
#include <sstream>
#include <unistd.h>
#include <iostream>
#include <cstdio>
#include <graphics.h>
#include <fstream>
#include <string>
#include <algorithm> //std::sort for array of structs sorting based on struct
// integer
Grid grid;
highScore scoreArray[100];
// functions to check game state for win or loss or can make moves
bool Game::canMove(){
bool canMove = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; y++){
if (grid.grid[x][y] == Grid::emptyCell) {
canMove = true;
return canMove;
}
// multiple if statements due to if grid[3][1] was being checked with
// grid[3+1][1] then it would loop around and check against grid[1][2]
// for an unknown reason, so to combat this i had to check specifically against
// the edge of the board
else if(y == 3 && x < 3){
if( grid.grid[x][y] == grid.grid[x+1][y] ){
canMove = true;
return canMove;
}
}
else if(x == 3 && y < 3){
if( grid.grid[x][y] == grid.grid[x][y+1] ){
canMove = true;
return canMove;
}
}
else if( ( x < 3 && y < 3 ) &&
(grid.grid[x][y] == grid.grid[x][y+1] ||
grid.grid[x][y] == grid.grid[x+1][y]) ) {
canMove = true;
return canMove;
}
}
}
return canMove;
}
bool Game::checkWin(){
bool win = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; y++){
if(grid.grid[x][y] == 2048){
win = true;
return win;
}
}
}
return win;
}
bool Game::checkLoss(){
bool loss = false;
if(canMove() == false ){
loss = true;
return loss;
}
return loss;
}
void Game::checkGameState(){
if(checkWin() == true) {
std::cout << "\n\n--------YOU WIN--------\n\n";
gameFinished = true;
writeHighScore();
}
else if(checkLoss() == true) {
std::cout << "\n\n--------YOU LOSE--------\n\n";
gameFinished = true;
}
}
// functions for initializing game/options
void Game::chooseFunction(){
while(1){
int function = 0;
std::cout << "\nPlease Choose A Function\n1) Play Game\n2) High Scores"
<< "\n3) Exit Program";
std::cout << "\nFunction : ";
std::cin >> function;
if (std::cin.fail() || function < 1 || function > 3) {
std::cin.clear();
std::cin.ignore(1000,'\n'); // this is to stop the validation from
// looping for each wrong character entered
std::cout << "Not a valid option, Please re-enter \n\n" ;
sleep(1);
}
else if (function == 1) {
std::cout << "------Launching Game------\n\n";
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
return ;
}
else if (function == 2) {
std::cout << "---Printing High Scores---\n";
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
printHighScores();
sleep(10);
}
else if (function == 3) {
std::cout << "-------Now Exiting------- \n\n" << std::flush ;
std::cout << "---------LOADING---------\n";
for(int x=0;x < 5;x++){
std::cout << "|||||" << std::flush;
sleep(1);
}
exit(0);
}
}
}
// This function is called upon a win, and writes the high score ,of those who
// win the game, into a text file under the format of SCORE - NAME
void Game::writeHighScore(){
std::string name;
std::cout << "\nEnter Name To Store High Score ( Max 16 Characters )\n"
<< "Name : ";
std::getline(std::cin,name);
// this is to stop the string being over 16 characters
if(std::cin.fail() || name.length() > 16){
std::cout << "\n\nPlease Enter A Max of 16 Characters\n\n";
writeHighScore();
return;
}
else{
// This opens the output stream to the high scores text file
// and immediately points to the next free line in the file
std::ofstream HighScore;
HighScore.open ("HighScores.txt", std::ios::app);
HighScore << grid.totalScore << " "<< name << std::endl;
HighScore.close();
return;
}
}
// simple comparator function to be used with std::sort in order to sort
// the array of structs containing scores and their respective player names
bool sortScore(highScore a,highScore b){
return a.score > b.score;
}
// this function prints the high scores from the text file, however
// im not sure how to sort a text file each time its appended, so instead
// when this function is called, it seperates the lines of the files into
// the score and their respective player name, these are stored in a struct
// object for each line, and then the array of structs is sorted using
// std::sort and the comparator function and then the first 10 scores and names
// in the struct array are printed, TLDR, prints Top 10 scores :)
//
// not on the spec for the assignment but i enjoyed learning about how
// i would go about making something like this :)
void Game::printHighScores() { // function to choose and print ascii art
std::ifstream highScores;
highScores.open("HighScores.txt");
std::string line;
int i=0;
if(!highScores){
std::cout << "\nCould Not Open HighScores.txt";
sleep(2);
return;
}
else{
while(getline(highScores, line)){
std::istringstream iss(line);
int score;
std::string name;
// this seperates out the score and the name string from each line in the file
if(!(iss >> score && iss.ignore() && std::getline(iss,name))){
break;
}
// this adds to the array of structs defined in the header file
scoreArray[i].score = score;
scoreArray[i].name = name;
i++;
}
std::sort(&scoreArray[0],&scoreArray[100],sortScore);
}
// and finally... this prints the top 10 scores
std::cout << "\n\n-------HIGH SCORES-------\n\n";
for(int i=0; i<10; i++){
std::cout <<i+1<<") "<<scoreArray[i].score<<" - "<<scoreArray[i].name
<<"\n";
}
}
行
highScore scoreArray[100];
在您的 header 中,只要包含此 header 就声明一个变量。我假设 header 包含在多个源文件中。
将其移至 .cpp
并将其添加 extern
至 header。
基本上,对于包含此 header 的每个源文件,您要声明一个名为 scoreArray
的变量。每个包含此 header 的 .cpp
都将声明其自己的 scoreArray
。链接器在执行链接操作时,会遇到两个同名变量,无法确定哪个变量“正确”,因此它会放弃并生成您所看到的错误。
因此,您需要将定义移动到 .cpp
中,并在 header 中将其作为 extern
引用。 (有几种不同的方法。选择最适合您的方法。)