我敢肯定,未定义的符号/参考感觉像是在这里被打死的话题,但是我遇到了一个奇怪的问题。有关一些背景信息,请参见我的previous question。
我正在开发一个小程序,它可以很好地编译,没有警告,错误或任何东西。然后,我更新了CMake,出现了以下错误:
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string(char const*)", referenced from:
GetName() in n2-af52d6.o
Expression() in n2-af52d6.o
Term() in n2-af52d6.o
GetNum() in n2-af52d6.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string()", referenced from:
GetName() in n2-af52d6.o
GetNum() in n2-af52d6.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::operator+=(char)", referenced from:
GetName() in n2-af52d6.o
GetNum() in n2-af52d6.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我认为这很奇怪,因为这些错误似乎来自标准库本身。
这是完整的程序:
//
// ncc.cpp
// Nathanael Epps
//
#include <string>
#include <iostream>
#include <sstream>
typedef std::string string;
static char look = '\0';
static const string Cmt = "## ";
static const string Tab = "\t";
static const string TabTab = Tab + Tab;
static const string TabTabTab = TabTab + Tab;
static void GetChar()
{
look = getchar();
while (look == ' ' || look == '\t')
look = getchar();
}
template <class T>
static string ToString(T x)
{
std::stringstream ss;
ss << x;
return ss.str();
}
static void Error(string mssg)
{
fprintf(stderr, "\n%s", mssg.c_str());
}
static void Abort(string mssg)
{
Error(mssg);
exit(0);
}
static void Expected(string expected)
{
Abort(expected + " expected.\n");
}
static void Match(char x)
{
if (x == look)
GetChar();
else
Expected(string("\"") + x + "\"");
}
static bool IsAlpha(char c)
{
c = toupper(c);
return 'A' <= c && c <= 'Z';
}
static bool IsDigit(char c)
{
return '0' <= c && c <= '9';
}
static bool IsAlNum(char c)
{
return IsAlpha(c) || IsDigit(c);
}
static string GetName()
{
if (!IsAlpha(look))
Expected("Alpha");
std::string name;
while (IsAlNum(look)) {
name += look;
GetChar();
}
return name;
}
static string GetNum()
{
if (!IsDigit(look))
Expected("Integer");
string num;
while (IsDigit(look)) {
num += look;
GetChar();
}
return num;
}
static void EmitLn(string s)
{
printf("\t%s\n", s.c_str());
}
static void EmitLn(char c)
{
printf("\t%c\n", c);
}
static void WriteLn(string s)
{
printf("%s\n", s.c_str());
}
static void Init()
{
GetChar();
}
static void Identifier()
{
auto name = GetName();
if (look == '(')
{
Match('(');
Match(')');
EmitLn("movq" + Tab + "$0, %rax");
EmitLn("callq" + Tab + "_" + name + TabTab + Cmt + "Leaves result in %rax");
}
else
{
EmitLn("movq" + Tab + name + "(%rip), %rax");
}
}
static void Expression();
static void Factor()
{
if (look == '(')
{
Match('(');
Expression();
Match(')');
}
else if (IsAlpha(look))
{
Identifier();
}
else
{
EmitLn("movq" + Tab + "$" + GetNum() + ", %rax");
}
}
static void Multiply()
{
Match('*');
Factor();
EmitLn("popq" + Tab + "%rbx");
EmitLn("imulq" + Tab + "%rbx, %rax");
EmitLn("movq" + Tab + "$0, %rdx");
}
static void Divide()
{
Match('/');
Factor();
// Right now, stack has top number
// %rax has bottom number
// move the bottom number to %rbx
EmitLn("movq" + Tab + "%rax, %rbx");
// move the top number to %rdx:%rax
EmitLn("popq" + Tab + "%rax");
EmitLn("cqto" + TabTabTab + Cmt + "%rax --> %rdx:%rax");
// do division
EmitLn("idivq" + Tab + "%rbx");// + TabTab + Cmt + "leaves result in %rax");
// clear %rdx
EmitLn("movq" + Tab + "$0, %rdx");// + Tab + Cmt + "clear %rdx");
}
static void Term()
{
Factor();
while (look == '*' || look == '/')
{
EmitLn("pushq" + Tab + "%rax");
if (look == '*')
Multiply();
else if (look == '/')
Divide();
else
Expected("Mult/Div Op");
}
}
static void Add()
{
Match('+');
Term();
EmitLn("popq" + Tab + "%rbx");
EmitLn("addq" + Tab + "%rbx, %rax");
}
static void Sub()
{
Match('-');
Term();
EmitLn("popq" + Tab + "%rbx");
EmitLn("subq" + Tab + "%rbx, %rax");
EmitLn("neg " + Tab + "%rax");
}
static bool IsAddop(char c)
{
return c == '+' || c == '-';
}
static void Expression()
{
if (IsAddop(look))
EmitLn("movq" + Tab + "$0, %rax");
else
Term();
while (IsAddop(look))
{
EmitLn("pushq" + Tab + "%rax");
if (look == '+')
Add();
else if (look == '-')
Sub();
else
Expected("Add/Sub Op");
}
}
static void Assignment()
{
auto name = GetName();
Match('=');
Expression();
//EmitLn("movq" + Tab + "%rax, " + name + "(%rip)");
EmitLn("movq" + Tab + "%rax, (variable " + name + ")");
}
static string NewLabel()
{
static unsigned count = 0;
return "L" + ToString(count++);
}
static void PostLabel(string lname)
{
WriteLn(lname + ":");
}
static void Condition()
{
EmitLn("<condition>");
}
static void Other()
{
EmitLn(look);
GetChar();
}
static void Block();
static void DoIf()
{
Match('i');
string l = NewLabel();
Condition();
EmitLn("jne" + Tab + l);
Block();
Match('e');
PostLabel(l);
}
static void Block()
{
while (look != 'e')
{
if (look == 'i')
DoIf();
else
Other();
}
}
static void Program()
{
Block();
if (look != 'e')
Expected("e");
EmitLn(Cmt + "Clean up stack, and such");
EmitLn("retq");
GetChar();
}
int main()
{
Init();
(void) Assignment;
Program();
if (look != '\n')
Expected("Newline");
return EXIT_SUCCESS;
}
但是,从函数中删除static
限定词会使错误消失。 (此外,如果您还没有弄清楚,该程序就是一个小的编译器。)
有什么作用?
编辑:
我通常只需输入即可链接
g++ ncc.cpp -std=c++14 -Wall -o ncc
运行g++ --version
可以做到这一点:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin17.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
这个问题不是this question的重复,因为答案是关于在文件作用域声明的静态变量导致文件本身中未定义符号,而我的问题是关于在文件作用域声明的静态函数导致了文件中未定义的引用标准库。
答案 0 :(得分:1)