C-1 入门知识

    技术2022-07-11  90

    笔者在WIN10和VC6.0下学习的笔记。

    标题

    编译预处理编译和汇编链接

    编译

    在VC安装目录C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin中就是IDE编译套件。 目录文件信息如下:

    cl.exe link.exe c1.dll c2.dll c1xx.dll

    其中cl为编译器(command line),其实现位于c1.dll c2.dll c1.dll.而link.exe 便是链接工具.

    首先一个最简单的hello.cpp如下:

    #include <stdio.h> void main(){ printf("bb"); printf("aa"); }

    编译的步骤大致分为四步骤: 1.预编译 2.编译 3.汇编 4.链接

    关于这几步网上到处是轮子,详情请参阅:c编译流程

    我们在vc提供的编译套件中手动实现这几步。

    预处理

    cl /p hello.cpp 预编译会将include展开放入生成的hello.i文件中.(关于更多编译选项 可输入 cl -help查看或c编译选项)

    #line 1 "Cpp1.cpp" #line 1 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" int __cdecl _fileno(FILE *); #line 307 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" int __cdecl _flushall(void); FILE * __cdecl fopen(const char *, const char *); int __cdecl fprintf(FILE *, const char *, ...); int __cdecl fputc(int, FILE *); int __cdecl _fputchar(int); int __cdecl fputs(const char *, FILE *); size_t __cdecl fread(void *, size_t, size_t, FILE *); FILE * __cdecl freopen(const char *, const char *, FILE *); int __cdecl fscanf(FILE *, const char *, ...); int __cdecl fsetpos(FILE *, const fpos_t *); int __cdecl fseek(FILE *, long, int); long __cdecl ftell(FILE *); size_t __cdecl fwrite(const void *, size_t, size_t, FILE *); int __cdecl getc(FILE *); int __cdecl getchar(void); int __cdecl _getmaxstdio(void); char * __cdecl gets(char *); int __cdecl _getw(FILE *); void __cdecl perror(const char *); int __cdecl _pclose(FILE *); FILE * __cdecl _popen(const char *, const char *); int __cdecl printf(const char *, ...); int __cdecl putc(int, FILE *); int __cdecl putchar(int); int __cdecl puts(const char *); int __cdecl _putw(int, FILE *); int __cdecl remove(const char *); int __cdecl rename(const char *, const char *); void __cdecl rewind(FILE *); int __cdecl _rmtmp(void); int __cdecl scanf(const char *, ...); void __cdecl setbuf(FILE *, char *); int __cdecl _setmaxstdio(int); int __cdecl setvbuf(FILE *, char *, int, size_t); int __cdecl _snprintf(char *, size_t, const char *, ...); int __cdecl sprintf(char *, const char *, ...); int __cdecl sscanf(const char *, const char *, ...); char * __cdecl _tempnam(const char *, const char *); FILE * __cdecl tmpfile(void); char * __cdecl tmpnam(char *); int __cdecl ungetc(int, FILE *); int __cdecl _unlink(const char *); int __cdecl vfprintf(FILE *, const char *, va_list); int __cdecl vprintf(const char *, va_list); int __cdecl _vsnprintf(char *, size_t, const char *, va_list); int __cdecl vsprintf(char *, const char *, va_list); #line 363 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" FILE * __cdecl _wfsopen(const wchar_t *, const wchar_t *, int); #line 369 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" wint_t __cdecl fgetwc(FILE *); wint_t __cdecl _fgetwchar(void); wint_t __cdecl fputwc(wint_t, FILE *); wint_t __cdecl _fputwchar(wint_t); wint_t __cdecl getwc(FILE *); wint_t __cdecl getwchar(void); wint_t __cdecl putwc(wint_t, FILE *); wint_t __cdecl putwchar(wint_t); wint_t __cdecl ungetwc(wint_t, FILE *); wchar_t * __cdecl fgetws(wchar_t *, int, FILE *); int __cdecl fputws(const wchar_t *, FILE *); wchar_t * __cdecl _getws(wchar_t *); int __cdecl _putws(const wchar_t *); int __cdecl fwprintf(FILE *, const wchar_t *, ...); int __cdecl wprintf(const wchar_t *, ...); int __cdecl _snwprintf(wchar_t *, size_t, const wchar_t *, ...); int __cdecl swprintf(wchar_t *, const wchar_t *, ...); int __cdecl vfwprintf(FILE *, const wchar_t *, va_list); int __cdecl vwprintf(const wchar_t *, va_list); int __cdecl _vsnwprintf(wchar_t *, size_t, const wchar_t *, va_list); int __cdecl vswprintf(wchar_t *, const wchar_t *, va_list); int __cdecl fwscanf(FILE *, const wchar_t *, ...); int __cdecl swscanf(const wchar_t *, const wchar_t *, ...); int __cdecl wscanf(const wchar_t *, ...); FILE * __cdecl _wfdopen(int, const wchar_t *); FILE * __cdecl _wfopen(const wchar_t *, const wchar_t *); FILE * __cdecl _wfreopen(const wchar_t *, const wchar_t *, FILE *); void __cdecl _wperror(const wchar_t *); FILE * __cdecl _wpopen(const wchar_t *, const wchar_t *); int __cdecl _wremove(const wchar_t *); wchar_t * __cdecl _wtempnam(const wchar_t *, const wchar_t *); wchar_t * __cdecl _wtmpnam(wchar_t *); #line 414 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" #line 415 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" #line 418 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" //省略一大批 int __cdecl fcloseall(void); FILE * __cdecl fdopen(int, const char *); int __cdecl fgetchar(void); int __cdecl fileno(FILE *); int __cdecl flushall(void); int __cdecl fputchar(int); int __cdecl getw(FILE *); int __cdecl putw(int, FILE *); int __cdecl rmtmp(void); char * __cdecl tempnam(const char *, const char *); int __cdecl unlink(const char *); #line 463 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" } #line 467 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" #pragma pack(pop) #line 471 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" #line 473 "C:\\Program Files (x86)\\Microsoft Visual Studio\\VC98\\include\\stdio.h" #line 2 "hello.cpp" void main(){ printf("bb"); printf("aa"); }

    第一个问题,我们的include<stdio.h>会首先去环境变量的include寻找的对应的头文件,如果没有找到那么将去编译目录 也就是hello.cpp本文件所在目录寻找stdio.h。

    笔者所在电脑的include环境变量:

    C:\Program Files (x86)\Microsoft Visual Studio\VC98\atl\include; C:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\include; C:\Program Files (x86)\Microsoft Visual Studio\VC98\include

    如果开发者用双引号寻找头文件(include "")那么首先会去编译目录 helllo.cpp寻找,如果找不到才会寻找环境变量include。

    另外可以在预编译的文件中可以看到导入的头文件具体位置。

    编译和汇编

    笔者并没有在vc编译选项中找到,所以我就干脆把这两步骤合为一步。

    cl \c hello.i 其中\c选项为编译但是不连接,hello.i 是预处理后的文件. 运行后目录将生成一个 二进制hello.obj文件,此文件可以用winhex查看。

    链接

    c语言要运行必须链接实现的实现库,比如我们的include<stdio.h>的printl函数,只是在预处理的时候导入的声明然而具体的实现其没有,所以我们必须借助link.exe链接并生成可执行文件。

    我们查看msdn文档的printf函数,了解到printf 实现库存在三个库中,分别为LIBC,LIBCMT,MSVCRT,分别对应单线程, 多线程,Microsoft visual C RUN TIME版本实现,我们这里只需要单线程版本。

    所以 我们键入如下命令link hello.obj LIBC.LIB完成最终的程序并生成Hello.exe

    Processed: 0.013, SQL: 12