Translation unit v.s Compilation unit

一句话, 二者表示的是the same things。 关于这个term的定义, C++和C 语言的相关的定义基本没有保持一致(unchanged)。

C的早期标准的定义如下:

C89 2.1.1.1

The text of the program is kept in units called source files in this Standard. A source file together with all the headers and source files included via the preprocessing directive #include , less (除掉)any source lines skipped by any of the conditional inclusion preprocessing directives, is called a translation unit。

在C++ 的最新的标准中, 定义如下:

C++14 (CD n3690) 2.1[lex.separate]/1

The text of the program is kept in units called source files in this International Standard. A source file together with all the headers and source files included via the preprocessing directive #include, less any source lines skipped by any of the conditional inclusion preprocessing directives, is called a translation unit.

在C语言标准中, 没有compilation unit 这个term,  compilation unit这个term只出现在C++ 的某些地方。 目的是为了将C++和C的语言区别开来。 其实和translation指的是同一个东西。

我们的编译器的任务collects 程序的源文件和#include连同出现的编译预处理包含进来的的头文件, 去掉源文件中的条件控制编译语句等, 组成一个translation unit, 然后将这个translation unit 编译成为目标文件(.o), 注: 目标文件(.o file)内容就是由object code , 是relocatable format machine code that is usually not directly executable. 即.o 文件是可以重新配置的机器代码, 通常并不是可以直接执行的。 .o 文件是有compiler 产生的。 用于作为linker(链接器)的输入, linker 利用输入的各种.o 文件, 组装成一个可执行(executable)的文件或者库(library)。(by combining parts of object files)。


下面举一个解释C++程序从预处理, 到编译, 再到链接生成可执行文件的各个步骤。

When you invoke your C++ compiler,
the C preprocessor accepts a source file and emits a translation unit,
the C++ compiler proper accepts the translation unit
and emits assembler code(汇编码),
the assembler accepts the assembler code and emits machine code and
the link editor(linker)accepts the machine code,
loads it into an executable program file
along with the required objects from library archives
and resolves all of the links.

When the C preprocessor reads your source file,
it includes the header files in the translation unit,
reads and processes all of the macros
then discards all of the macros when it has finished.
It does *not* remember macro definitions
when it processes the next source files
so, if the next source file includes the same header file,
the header file will be read again
and any external function definition in that header
will be included in the next translation unit as well.
The link editor will discover multiple function definitions(多个函数定义(违反了C++ 的ODR(one definition rule)规则))
if it trys to link the resulting machine code files together(会发生编译器链接报错).
If, instead, you qualify the function definition as inline or static,
the compiler will label them as "local" links(局部链接, 所以当然不会报错多个函数定义)
so the link editor will not complain.

再看看另一个解答

I highly suggest that this be added to the FAQ.
You have Source Code files:
a.cpp
b.cpp
s.cpp

You have 1 Header file:

b.hpp

Both a.cpp and s.cpp include b.hpp.
The three source code files get compiled into object files:

a.obj b.obj s.obj

And they're passed on to the linker.

不同的源文件在编译的时候是独立的生成.o 文件。
The linker (链接器)sees a function, Monkey, in a.obj AND in s.obj, hence a multiple
definition.


So how do you get away with putting inline functions into a header file?
They have internal linkage, ie. these functions aren't presented to the
linker. The "static" is implied in inline functions.

  1. Ok, the C/C++compiler  actually works in a series of stages, more or less like this:
  2. The pre-processor - strips out comments, expands #define macros and #include lines, etc.
  3. The compiler - parses your source code and builds assembly output from it
  4. The assembler - takes that assembly code and builds an object file out of it
  5. The linker - takes some of those object files and such, and builds an executable out of it
  6. The loader - not generally part of the compiler suite, but part of the OS. Takes your executable and actually tries to load and run it. This may be more complicated than it sounds - for instance, your program might have unresolved symbols in it even after the linker goes over it, for instance if you used a shared library (eg. .so in unix or .dll in windows) which is supposed to be linked in at run time.


A compiler's job is really to transform your code from the human-readable form (source code) to a form which means something from the computer's standpoint. This doesn't necessarily mean "executable" To be specific, your C compiler is actually supposed to turn C source code into object files. An object file is an intermediate form, where all the code has been understood and processed by the compiler, but it's not ready to run yet because it's only the code from one file. If your program is made up of multiple files, each file gets built into an object file, and there are calls between the object files that have not been resolved yet.

Hence, the object files still need to be linked together before all the symbols make sense. For example:

Suppose you have 2 files, main.c and spoo.c (plus a header for spoo), where there's a function in spoo.c called, oh, shall we say, spoo() which is called from themain.c file. Well, when you go to compile main.c and spoo.c into their respective object files (main.o and spoo.o) the compiler isn't going to look at the other source file, so when it builds main, it doesn't know what to make of the spoo function. It knows the spoo function exists, because the header declared "Hey, there's this function void spoo(void);" but it doesn't know what spoo actually does, just that there is a function called spoo. So, it basically puts in a placeholder for spoo. Eg, it puts "I'm calling void spoo(void) here, but I don't know what it is" in main.o when it compiles it.

So, how does one actually get a program that runs? The linker to the rescue! The linker is a program that, given a bunch of object files, resolves all the unresolved symbols (those place holders) in them and produces your actual executable.

What's up with g++ actually producting executables then? Well, g++ is technically a group of programs, one of which is the compiler, one of which is the linker, etc. When you invoke it on a source file, it typically assumes you want an executable, so it calls the linker for you. Nice ot it, no?







org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: WorkflowScript: 14: Invalid parameter "failFast", did you mean "unit"? @ line 14, column 50. eout(time: 48, unit: 'HOURS', failFast: ^ WorkflowScript: 16: Invalid step "parallel" used - not allowed in this context - The parallel step can only be used as the only top-level step in a stages step block @ line 16, column 6. parallel { ^ WorkflowScript: 18: Invalid step "stage" used - not allowed in this context - The stage step cannot be used in Declarative Pipelines @ line 18, column 7. stage('version-A35-2290000204') { ^ 3 errors at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1107) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:624) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:602) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:579) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:323) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:293) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox$Scope.parse(GroovySandbox.java:163) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:190) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:175) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:568) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:518) at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:336) at hudson.model.ResourceController.execute(ResourceController.java:101) at hudson.model.Executor.run(Executor.java:442) Finished: FAILURE
07-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值