21点程序中架构x86_64的未定义符号

C++ Undefined symbols for architecture x86_64 in blackjack program

本文关键字:未定义 符号 x86 程序 21点      更新时间:2023-10-16

我在c++中编程一个21点游戏,遇到这个问题几次,即使我已经在谷歌上搜索了,他们的解决方案仍然不适合我,所以我想知道它在哪里出了问题。

在Clion中编译时,错误如下:

架构的未定义符号x86_64:

"Blackjack::stand()",引用自:

_main in main.cp .o

ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1(使用-v to。见调用)

main.cpp:

#include <iostream>
#include "blackjack.h"
using namespace std;
int main() {
    Blackjack bj;
    for (int i = 0; i < 11; ++i) {
        bj.dealerCards.push_back(i);
    }
    for (int i = 0; i < 10; ++i) {
        bj.playerCards.push_back(i);
    }
    bj.stand();
    return 0;
}

blackjack.h:

#pragma once
#include <vector>
#include <numeric>
using namespace std;
class Blackjack {
public:
    vector<int> desk; // public only for test, should be protected or private
public: // public only for test, should be protected
    vector<int> dealerCards;
    vector<int> playerCards;
public:
    int hit() {};
    void stand();
};

blackjack_stand.h:

#pragma once
#include <iostream>
#include <numeric>
#include "blackjack.h"
void Blackjack::stand() {
    ......
}

在您的源代码文件结构中,虽然blackjack_stand.h包含实现,但它确实根本没有编译,因为编译器通常不直接编译头文件。

您应该将blackjack_stand.h重命名为blackhack_stand.cpp并将该文件与main.cpp一起编译。

Blackjack::stand的定义不应该在头文件中。头文件用于声明,而不是用于定义(参见下面的inline异常)。

为了理解为什么,我们需要学习两个新术语:

  • 声明:通知编译器新的类、变量或函数。在大多数情况下应该在头文件中。例如,blackjack.h中的void stand();是声明。
  • 定义:实际实现此函数的类函数。在大多数情况下应该在.cpp文件中(参见下面的例外)。例如,void Blackjack::stand() { ... }是一个定义。

当代码编译时,编译器只会读取和编译.cpp文件中的所有常规函数一次,但它会读取每个.cpp文件的#include中的头文件。通过分离定义和声明,我们可以确保代码只在程序中存在一次。

Exception - inline functions:然而,有时我们有一个小函数,我们并不真正关心它的实现是否会重复多次。因此,可以在函数定义之前使用内联并将其放在头文件中,也可以将其定义为类的一部分:

class B
{
    void foo() { std::cout << "This code will be in every place it called" << std::endl; }
};
inline bar() { std::cout << "This function too!" << std::endl;  }

总结

为了确保只编译一次,我们应该总是在.cpp文件中定义函数,并在头文件中声明它们。