C++ 编译与链接面试题

1. C++程序的编译过程是什么?

答案:

  • 四个阶段预处理(Preprocessing)处理#include、#define等指令展开宏条件编译生成.i文件编译(Compilation)将预处理后的代码转换为汇编代码语法检查、语义分析优化生成.s文件汇编(Assembly)将汇编代码转换为机器码生成目标文件.o或.obj链接(Linking)将多个目标文件链接成可执行文件解析符号引用重定位生成可执行文件
  • 命令示例
# 预处理
g++ -E main.cpp -o main.i

# 编译
g++ -S main.cpp -o main.s

# 汇编
g++ -c main.cpp -o main.o

# 链接
g++ main.o -o main

C++面试题合集 : https://www.nowcoder.com/creation/manager/columnDetail/MJ4oG8

2. 什么是头文件?为什么需要头文件保护?

答案:

  • 头文件作用声明函数、类、变量提供接口代码复用
  • 头文件保护防止重复包含避免重定义错误
  • 传统方法(Include Guard)
#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass {
    // ...
};

#endif
  • 现代方法(#pragma once)
#pragma once

class MyClass {
    // ...
};
  • 对比pragma once更简洁Include Guard更标准现代编译器都支持#pragma once

3. 什么是链接?静态链接和动态链接的区别?

答案:

  • 链接定义将多个目标文件组合成可执行文件解析符号引用分配内存地址
  • 静态链接编译时将库代码复制到可执行文件生成独立的可执行文件文件大,但不依赖外部库Windows: .lib, Linux: .a
  • 动态链接运行时加载库多个程序共享同一库文件小,节省内存需要库文件存在Windows: .dll, Linux: .so
  • 对比
# 静态链接
g++ main.cpp -static -o main

# 动态链接(默认)
g++ main.cpp -o main
  • 优缺点静态:独立、快速启动,但文件大动态:节省空间、易更新,但依赖外部库

4. 什么是符号?extern关键字的作用?

答案:

  • 符号定义函数名、变量名等标识符链接器通过符号解析引用
  • extern关键字声明外部符号不分配内存告诉编译器符号在其他文件定义
  • 使用示例
// file1.cpp
int globalVar = 10;

void func() {
    // ...
}

// file2.cpp
extern int globalVar;  // 声明
extern void func();    // 声明

void use() {
    cout << globalVar;
    func();
}
  • extern "C"使用C链接方式避免C++名称修饰用于C/C++混合编程
extern "C" {
    void c_function();
}

5. 什么是名称修饰(Name Mangling)?

答案:

  • 定义编译器将函数名编码包含参数类型、命名空间等信息支持函数重载
  • 示例
void func(int);
void func(double);
void func(int, int);

// 编译后可能变成
// _Z4funci
// _Z4funcd
// _Z4funcii
  • 查看修饰名
# Linux
nm main.o

# Windows
dumpbin /symbols main.obj
  • 问题不同编译器修饰规则不同导致二进制不兼容
  • 解决方法使用extern "C"使用相同编译器使用标准ABI

6. 什么是链接错误?常见的链接错误有哪些?

答案:

  • 未定义引用(Undefined Reference)声明了但未定义忘记链接库拼写错误
undefined reference to `func()'
  • 重复定义(Multiple Definition)同一符号定义多次头文件中定义函数
multiple definition of `globalVar'
  • 解决方法
// 错误:头文件中定义
// header.h
int globalVar = 10;  // 错误

// 正确:头文件中声明
// header.h
extern int globalVar;

// source.cpp
int globalVar = 10;
  • inline函数可以在头文件中定义不会导致重复定义

7. 什么是编译单元?

答案:

  • 定义一个.cpp文件及其包含的所有头文件编译器独立编译每个编译单元生成一个目标文件
  • 示例
main.cpp
  #include "a.h"
  #include "b.h"

// 编译单元包含:main.cpp + a.h + b.h
  • 影响编译时间头文件修改会重新编译所有包含它的编译单元前向声明可以减少依赖
  • 优化减少头文件包含使用前向声明使用Pimpl惯用法

8. 什么是前向声明?什么时候使用?

答案:

  • 定义声明类或函数,不提供完整定义告诉编译器类型存在
  • 使用场景
// 前向声明
class B;

class A {
    B* ptr;  // 指针,可以使用前向声明
    // B obj;  // 错误,需要完整定义
    void func(B& b);  // 引用,可以使用前向声明
};

// B的完整定义
class B {
    // ...
};
  • 优势减少编译依赖加快编译速度避免循环依赖
  • 限制只能用于指针和引用不能访问成员不能创建对象

9. 什么是Pimpl惯用法?

答案:

  • 定义Pointer to Implementation将实现细节隐藏在指针后减少编译依赖
  • 实现
// widget.h
class Widget {
public:
    Widget();
    ~Widget();
    void doSomething();
    
private:
    class Impl;  // 前向声明
    unique_ptr<Impl> pImpl;
};

// widget.cpp
class Widget::Impl {
public:
    void doSomething() {
        // 实现
    }
    
private:
    // 私有成员
    int data;
    vector<int> vec;
};

Widget::Widget() : pImpl(make_unique<Impl>()) {}
Widget::~Widget() = default;

void Widget::doSomething() {
    pImpl->doSomething();
}
  • 优势隐藏实现细节减少编译依赖二进制兼容性加快编译速度
  • 缺点额外的间接访问内存分配开销代码复杂度增加

10. 如何优化编译时间?

答案:

  • 减少头文件包含使用前向声明只包含必要的头文件在.cpp中包含,而非.h
  • 使用预编译头文件
// stdafx.h
#include <iostream>
#include <vector>
#include <string>

// 编译
g++ -x c++-header stdafx.h -o stdafx.h.gch
  • 并行编译
# Make
make -j4

# CMake
cmake --build . -j4
  • 使用ccache缓存编译结果加速重复编译
  • 模块化设计减少依赖使用接口类Pimpl惯用法
  • 增量编译只编译修改的文件使用构建系统(Make、CMake)
  • 编译器优化
全部评论

相关推荐

1.8&nbsp;腾讯官网直投,凌晨把综合测评答完了(2h)。1.13&nbsp;网易互娱官网直投。1.15&nbsp;腾讯一面面邀。1.20&nbsp;早上腾讯一面技术面,感觉良好,下午两位面试官加了微信,邀请二面。1.22&nbsp;腾讯二面总监面(难度直线飙升),压力测试加摸底式技术追问,对线了很久,应对得最不从容的一次。结束后脑袋嗡嗡作响,对自己的表现感到不满意,心情比较难过。1.23&nbsp;早上网易&nbsp;HR&nbsp;加好友并发了&nbsp;JD&nbsp;,看了一下是人工智能+TA方向,感觉不错。HR&nbsp;表示主管刷到我的作品集视频,希望走提前一点的流程,但偏日常实习,婉拒,表示想先走官网看看。1.23&nbsp;下午腾讯一面面试官邀请语音通话并发了两道测试题(意思是二面已过),让我二选一,面试官开玩笑说都做完也可以。悬着的心终于放下了。当晚网易官网测试题直发(但与腾讯测试题时间冲突)。1.24&nbsp;疯狂熬夜,基本完成腾讯第一道测试题,同时找到了第二道题的思路,决定两道题都做,继续攻坚克难(平均每天4h睡眠)。1.26&nbsp;腾讯测试题工程文件、技术文档、视频演示提交,处于身心俱疲状态。当晚收到第二题的迭代要求,ddl27号晚上,强撑继续熬夜肝。1.27&nbsp;早上腾讯测试题迭代版提交。1.29&nbsp;腾讯两道测试题都顺利通过。收到网易测试题邮件催促,然而几乎零进度。比较疲惫。1.30&nbsp;早上腾讯&nbsp;HR&nbsp;面,当天云证。不太满意自己网易测试题的效果,截止日已到,遗憾放弃提交笔试。2.3&nbsp;网易又一位&nbsp;HR&nbsp;电话联系,希望另外给我发测试题,表示可以让我先去腾讯实习,网易的&nbsp;Offer&nbsp;入职时间灵活,可以暑期再入职,并可提供转正机会。反复博弈,本身欣赏网易氛围且有认识网易的小伙伴,欣然接受。晚上&nbsp;HR&nbsp;和业务沟通后表示给我免笔试(受宠若惊)。2.4&nbsp;网易一面面邀。2.6&nbsp;网易一面,虽然有些算法没答上来,但是作品集相关的问题答得没问题,当天过了。感觉面试官像主管,而且真的是把我的B站视频大概看了一下,连我以前喜欢玩什么游戏都知道,气氛一下变得融洽了起来。晚上邮件二面面邀。2.9&nbsp;腾讯官网流程卡在录用评估一个多星期了,比较焦虑。由于行程安排需要,并且临近春节,在群里友好催了一下腾讯二位面试官,结果秒发邮件,无&nbsp;OC&nbsp;直接&nbsp;Offer&nbsp;!戴上红围脖啦~2.10&nbsp;网易二面。因为没做笔试题,所以几乎还是和一面一样追问作品集,但只追问了一两个技术比较复杂的demo,相比一面,问题深度多上了几个level,而且比较发散,会考虑到实际开发的可能遇到的难题。两位面试官,几乎只是一位面试官在问,另一位面试官只在反问环节进行了解答。2.12&nbsp;网易方面最早联系我的那位&nbsp;HR&nbsp;邀请微信语音通话,表示网易方面想要给我发&nbsp;Offer&nbsp;,但是考虑到我这边已经有腾讯&nbsp;Offer&nbsp;了,需要我取舍一下,并反复强调网易的福利,继续博弈,婉拒了网易,希望暑期能够有机会再次合作。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务