puts "Hello world" in VC++

来源:互联网 发布:计算机二级c语言怎么考 编辑:程序博客网 时间:2024/05/16 23:43

本文所需的文件下载

http://download.csdn.net/source/3567384


我们现在做一件经典的事情,输出一行Hello world.

假设给你一台电脑和一个windows操作系统,然后什么都没装,你每次能安装一个程序,我们来看看能够做什么。


1.首先,你获得了记事本, Notepad.exe, 你输入了一行

output a string Hello world

现在你觉得output a string这个名字太长了,而Hello world和前面的混了。到底是output 'a string Hello world' 还是 output a string 'Hello world'呢?

你换了一下描述,缩写了一下,加了括号显得比较专业,于是成了

puts("Hello world");

保存为了C:\mydir\hello.cpp

(假定你新建了mydir这个目录)


[现在C:\mydir有hello.cpp一个文件]


2.现在你没法真正意义上的运行这句话,虽然你看到了Hello world的文字。

所以你要了VC++的编译器cl.exe,这里是VC2008下的, 以及相关的依赖dll(c1.dll,c1xx.dll,c2.dll,2052/clui.dll,mspdb80.dll)

假设你好在有一些命令行经验,如果没有,你打开了cmd,进入了C:\mydir(  输入C:回车 cd\mydir回车 )

然后你运行了

cl hello.cpp

现在CL给出了很奇怪的提示

hello.cpp(1) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
hello.cpp(1) : error C2440: “初始化”: 无法从“const char [12]”转换为“int”       没有使该转换得以执行的上下文

是什么意思呢。

这时候,某人告诉你说,光是一行命令是不够的,C语言还要有函数,于是你加了好看的花边:

void work(){puts("Hello world");}

这个时候

cl hello.cpp

提示说

hello.cpp(3) : error C3861: “puts”: 找不到标识符

[现在C:\mydir的文件是 hello.cpp cl.exe c1.dll c1xx.dll c2.dll 2052目录下的clui.dll mspdb80.dll]



3.既然这样,于是你想说明一下我有一个puts,通过查询手册,你加了puts的说明或声明:

看上去是这个样子的


int puts( const char * );void work(){puts("Hello world");}


于是

cl hello.cpp

提示说

cl: 命令行 error D8027 :无法执行“link.exe”

[现在C:\mydir的文件是 hello.cpp cl.exe c1.dll c1xx.dll c2.dll 2052目录下的clui.dll mspdb80.dll  link.exe  hello.obj]

4.于是你又要来了link.exe
cl hello.cpp

于是link提示说

/out:hello.exe
hello.obj
LINK : fatal error LNK1104: 无法打开文件“LIBCMT.lib”


不巧的是,你不能一次要求整个VC++,压缩包也不行,所以你选择了看LINK的帮助,并最终发现一个可能有关的选项:

  /nodefaultlib

同时你学会了从cl向link传送选项的方法

 /link

cl hello.cpp /link /nodefaultlib

然后link又提示说,必须定义入口点,本着缺哪里补哪里的精神,那就定义一个入口点。

由于我们刚才写的是work,所以入口名字就叫work了,puts这行代码是不算入口点也没有记号来表示它的。

然后link又提示说缺少子系统定义,那也定义一个。因为只是输出,没有窗口,可以就用console

于是我们最终的命令行是:

cl hello.cpp /link /nodefaultlib /entry:work /subsystem:console

现在link提示说

/out:hello.exe
/nodefaultlib
/entry:work
/subsystem:console
hello.obj
hello.obj : error LNK2019: 无法解析的外部符号 "int __cdecl puts(char const *)" (
?puts@@YAHPBD@Z),该符号在函数 "void __cdecl work(void)" (?work@@YAXXZ) 中被引用


hello.exe : fatal error LNK1120: 1 个无法解析的外部命令

[现在C:\mydir的文件是 hello.cpp cl.exe c1.dll c1xx.dll c2.dll 2052目录下的clui.dll mspdb80.dll  link.exe ]


5.因为提示说是外部符号,那么改这里可能是没用的。

事实上puts位于msvcrt.dll中,于是你又谷歌了一下,要来了lib.exe

新建了一个msvcrt.def文件,只写了哪里有函数和需要的函数名是哪个

LIBRARY msvcrtEXPORTS    puts

然后你运行

lib /def:msvcrt.def

我的32位编译器在这里有一行警告,提示没有指定机器形式,默认生成了x86文件

这时候生成了一个msvcrt.lib和一个msvcrt.exp

[现在C:\mydir的文件是 hello.cpp cl.exe c1.dll c1xx.dll c2.dll 2052目录下的clui.dll mspdb80.dll  link.exe lib.exe msvcrt.def msvcrt.lib msvcrt.exp hello.obj]



6.现在把生成的文件传给link,你会发现这里只要msvcrt.lib就够了。

cl hello.cpp /link msvcrt.lib /nodefaultlib /subsystem:console /entry:work

还是出现了问题

/out:hello.exe
msvcrt.lib
/nodefaultlib
/subsystem:windows
/entry:work
hello.obj
hello.obj : error LNK2019: unresolved external symbol "int __cdecl puts(char con
st *)" (?puts@@YAHPBD@Z) referenced in function "void __cdecl work(void)" (?work
@@YAXXZ)
hello.exe : fatal error LNK1120: 1 unresolved externals


这里要注意的是,我们为了时髦,扩展名用了cpp而不是c,那么cl会当作c++程序来编译hello.cpp。

然而你不幸被告知puts在msvcrt.dll中是c程序编译的,所以有必要在你的hello.cpp里面修改一下。

extern "C"{int puts(const char *);}void work(){puts("Hello world");}

然后运行

cl hello.cpp /link msvcrt.lib /nodefaultlib /subsystem:console /entry:work


用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.21022.08 版
版权所有(C) Microsoft Corporation。保留所有权利。


hello.cpp
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.


/out:hello.exe
msvcrt.lib
/nodefaultlib
/subsystem:console
/entry:work
hello.obj


似乎没有提示错误,键入hello.exe

Hello world

看,你成功了

[现在C:\mydir的文件是 hello.cpp cl.exe c1.dll c1xx.dll c2.dll 2052目录下的clui.dll mspdb80.dll  link.exe lib.exe msvcrt.def msvcrt.lib msvcrt.exp hello.obj hello.exe]


7.这就是这个经典例子的精简重现

原创粉丝点击