GCC/Java 编译问题解决指南

GCC/Java 编译问题解决指南

最近很多次碰到 GCC/Javac 向我提示编译错误(Compile-time Error) ,特地来总结一下如何更好的理解 GCC/Javac 等高级编译器的表述。

 

基本概念

Symbol 符号

大家可以暂且认为“符号”就是变量的意思。

声明(Declaration) 是指在程序中指明下文所需要的一个符号,但是这个符号具体的存储位置并不确定,需要编译器见到定义后才能确定。

定义 (Definition)是指  在程序中指定这个变量的实际存储位置,并确定的指明这个变量(可包含初始值)。

 

Type 类型

主要有下列几种Type

1. 系统自带的标量类型 

整数型(1bit/8bit/16bit/32bit/64bit/128bit) 以及有符号、无符号的组合。

浮点型 float/double/long double 主要遵循IEEE 754 定义。

复数型 umm, 这个可能用的比较少,提及一下。

BOOL 型(类似整数1bit型)真/假

空  (VOID) 这个其实也是一种类型

2. 结构类型 / UNION  类型

3. 数组类型

4. 指针类型

5. 函数类型(其实函数也是一种类型)

 

0. 文件相关

Cannot locate ..... 

请你确认你的Include Directory 列表里面有没有包含这个能追溯到这个文件的路径。

譬如 如果我的 #include <openssl/rsa.h> 意思为我的 Include Directory 列表里面不应包含 openssl 这个目录,而是应该包含openssl 所在的这个目录。

 

1. 变量相关

Undefined symbol

这个未定义的”符号“是指我们使用了一个未定义的符号。注意这里的提示是未定义的符号,这里有两种情况:

1. 有可能这个符号已经被声明,但是没有发现他的定义。

2. 这个符号根本不存在,(连声明都没有。)

 

 

2. 函数调用/定义

Parameter Mismatch

Ambiguious Call / Ambiguious Function / Ambiguious Reference

函数的声明和对应的实际传入的参数可能不符,这里需要注意两种情况。

1 : 函数可能存在多态(Polymorphism), 即多个函数名称一致,但参数不一致。这种情况下有可能产生编译器无法自动推断出我们想要调用的对应函数 

举个栗子:

我们定义了几个函数 

foo (int a);

foo (long b);

 

但实际上我们调用的时候写的是

void bar () {
  foo (0.3);
}

编译器看到这里就傻眼了,WHAT?这两个定义让我如何选择? 

这里需要注意到的是这种情况比较容易发生在变量的实际参数需要经过一些Casting (强制转换)才能满足定义要求的时候,这种时候我们就需要手动指定需要用哪个,(加上强制转换)即可。

void bar () {
  foo ((int) 0.3);
}

2. 函数可能在某个 .h 文件中,而我们没有引用这个.h 文件

#include <一个你没有的文件.h>

3. 函数定义可能被包裹在某个 #ifdef / #if 控制的这种可选择的部分内,然而这些宏开关并没有打开,这个时候我们就需要去仔细查看是不是我们的配置文件/Makefile/CMakeLists 选项,参数 出现了一些问题。

#ifdef SOME_THING_SHOULD_BE_OFF

int myvar;

#endif

 

3. 类型、结构、运算

Type mismatch 

1. 仔细检查是否有 某个类型 T 和 T* , T& 混淆的情况

void foo (int &p) {
...
}

void bar () {
    int samp;
    foo (&samp); //  这里的 &samp 的类型是 int *, 不符合上面的定义
}

void far () {
    int samp;
    foo (samp); //  这里的 samp 的类型是 int &, 符合上面的定义
}

2. 确认可否进行强制转换

Java 当中注意 bool 和整数、浮点数不可以进行转换

Java 之中标量转换仅限于 (byte,char,short,int,long,float,double) 注意char是无符号,其余有符号哦。

所有有精度损失的地方在Java 中最好加上显式强制转换,以告知编译器你充分了解你在做什么。

C/C++/Java 注意浮点数整数转换的精度损失。

 

3. 是不是 Unsigned 和 Signed 的问题

 

Incomplete Type

1. 请检查是否存在这个类型的定义、声明,大部份情况都是没有定义类型或者拼写错误。

2. Forwarding 相关: 我们在一些情况下使用Type的时候,编译器要求必须有可见的定义(声明是不足够的)

这些情况例如 嵌套的结构、结构数组,某些强制转换 等等,这个时候注意不要出现循环定义。

A包含B,B包含A,编译器会直接当场晕死。

 

 

 

 

4. 链接与运行时问题

Undefined Symbol / Unresolved external symbol

这个真的遇到无数次,主要有下面几种情况

譬如我有一个变量 在 a.cpp , 然鹅使用的地方在 b.cpp

我就会在 b.cpp 写一个 EXTERN 的变量声明

 

a.cpp

int somevar;

b.cpp

extern int somevar;

这种情况下 b.cpp 可以进行单文件编译,但是编译之后的代码肯定没有办法通过链接(因为有 somevar 这个变量没有定义,只有声明)这种时候就需要在链接时将两个Symbol归一化,然鹅 如果我们在运行 LD (连接器)的时候没有带上 a.cpp 生成的 a.o, 那么就会出现 Undefined Symbol 这个问题,

在MSVC 上面这个叫做LNK2001, Unresolved external symbol.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值