- 浏览: 4091379 次
最新评论
VC++ 6.0的小花招
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
<script type="text/javascript">
$(function () {
$("#btnSubmit").click(function () {
search();
});
$("#frmSearch").submit(function () {
search();
return false;
});
function search()
{
var url = "http://so.csdn.net/so/search/s.do?q=" + encodeURIComponent($("#inputSearch").val()) + "&u=" + username + "&t=blog";
window.location.href = url;
}
});
</script>
<script type="text/javascript">
new Ad(12, 'ad_commend');
</script>
<script type="text/javascript" src="http://csdnimg.cn/rabbit/cnick/cnick.js"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/newblog.min.js"></script><script type="text/javascript" src="http://medal.blog.csdn.net/showblogmedal.ashx?blogid=254649"></script><script type="text/javascript">
document.write('<script type="text/javascript" src="http://csdnimg.cn/pubfooter/js/publib_footer.js?' + Math.floor(new Date() / 120000).toString(36) + '="></' + 'script>');
</script><script type="text/javascript" src="http://passport.csdn.net/content/loginbox/login.js"></script><script type="text/javascript">document.write("<img src=http://counter.csdn.net/pv.aspx?id=24 border=0 width=0 height=0>");</script><script type="text/javascript" src="http://www.csdn.net/ui/scripts/Csdn/counter.js"></script><script type="text/javascript" src="http://ad.csdn.net/scripts/ad-blog.js"></script><script type="text/javascript" src="http://zz.csdn.net/js/count.js"></script><script type="text/javascript">
$(function () {
function __get_code_toolbar(snippet_id) {
return $("<a href='https://code.csdn.net/snippets/"
+ snippet_id
+ "' target='_blank' title='在CODE上查看代码片' style='text-indent:0;'><img src='https://code.csdn.net/assets/CODE_ico.png' width=12 height=12 alt='在CODE上查看代码片' style='position:relative;top:1px;left:2px;'/></a>"
+ "<a href='https://code.csdn.net/snippets/"
+ snippet_id
+ "/fork' target='_blank' title='派生到我的代码片' style='text-indent:0;'><img src='https://code.csdn.net/assets/ico_fork.svg' width=12 height=12 alt='派生到我的代码片' style='position:relative;top:2px;left:2px;'/></a>");
}
$("[code_snippet_id]").each(function () {
__s_id = $(this).attr("code_snippet_id");
if (__s_id != null && __s_id != "" && __s_id != 0 && parseInt(__s_id) > 70020) {
__code_tool = __get_code_toolbar(__s_id);
$(this).prev().find(".tools").append(__code_tool);
}
});
});
</script>
VC++ 6.0的小花招
许式伟
2006-2-18
Visual Studio系列中产品中,Visual Studio 6.0是最经典的一个版本,虽然后来有Visual Studio .NET 2003,以及2005,也确实添加了很多让我觉得激动的特性,但是从使用细节的细腻程度上来看,VS 6.0无疑是最棒的。我们一些同事甚至试图把2005的C++编译器独立的拿到Visual Studio 6.0中来用,也不愿意升级到.NET上来用,可见其魅力。
和VS 6.0这个产品的成熟相比,VC++ 6.0的编译器的的确确相对来说有些糟糕,其中最被诟病的是对模板技术支持很不好。下面我想做的一件事情,就是向那些继续留恋VC++ 6.0的朋友,介绍一些小花招,来避开VC++ 6.0的一些编译器缺陷。
1)for (type var=expression;;) 中变量var的作用域问题。
按照C++标准,这里定义的变量var出了for循环应该被销毁。也就是说下面这段代码是有效的:
for (int i = 0; i
func();
for (int i = 0; i 主题推荐
vc++
visual c++
namespace
技术
标准
猜你在找
<script type="text/javascript">
var searchtitletags = ' VC++ 6.0的小花招' + ',' + 'vc++,visual c++,namespace,技术,标准';
searchService({
index: 'blog',
query: searchtitletags,
from: 10,
size: 10,
appendTo: '#res-relatived',
url: 'recommend',
his: 2,
client: "blog_cf_enhance",
tmpl: '<dd style="background:url(http://static.blog.csdn.net/skin/default/images/blog-dot-red3.gif) no-repeat 0 10px;"><a href="#{ url }" title="#{ title }" strategy="#{ strategy }">#{ title }</a></dd>'
});
</script>
<script type="text/javascript">
new Ad(5, 'ad_bot');
</script>
<script type="text/javascript">
$(function ()
{
$("#ad_frm_0").height("90px");
setTimeout(function(){
$("#ad_frm_2").height("200px");
},1000);
if($("#comment_content").length>0)
{
$("#quick-reply").show();
$("#quick-reply").click(function(){
setEditorFocus();
});
}
var d_top = $('#d-top-a');
document.onscroll = function ()
{
var scrTop = (document.body.scrollTop || document.documentElement.scrollTop);
if (scrTop > 500)
{
d_top.show();
} else
{
d_top.hide();
}
}
$('#d-top-a').click(function ()
{
scrollTo(0, 0);
this.blur();
return false;
});
});
</script><style type="text/css">
.tag_list
{
background: none repeat scroll 0 0 #FFFFFF;
border: 1px solid #D7CBC1;
color: #000000;
font-size: 12px;
line-height: 20px;
list-style: none outside none;
margin: 10px 2% 0 1%;
padding: 1px;
}
.tag_list h5
{
background: none repeat scroll 0 0 #E0DBD3;
color: #47381C;
font-size: 12px;
height: 24px;
line-height: 24px;
padding: 0 5px;
margin: 0;
}
.tag_list h5 a
{
color: #47381C;
}
.classify
{
margin: 10px 0;
padding: 4px 12px 8px;
}
.classify a
{
margin-right: 20px;
white-space: nowrap;
}
</style>
func2();
而下面这段代码应该编译不过:
for (int i = 0; i
{
if (has_found_it())
{
handle_find_result();
break;
}
}
if (i == 100)
do_not_found();
然而VC++ 6.0对于第一段代码会报变量i重复定义错误,而第二段代码编译通过。
为了让VC++ 6.0的for语句看起来符合C++标准,你可以这样做:
#define for if (0); else for
你会发现很有趣,这样define一下后,VC++ 6.0的for语句完全符合C++标准了!而且由于编译器的优化,Release版本不会增加任何额外的开销。
喜欢“钻牛角尖”的朋友可能会说:嗯,不错的主意。但是——为什么不这样做:
#define for if (1) for
嗯?看起来也可以。还是让我们看一个用例:
if (cond)
for (int i = 0; i
<!-- Baidu Button BEGIN -->
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "1", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script><!-- Baidu Button END --><!--192.168.100.35--><!-- Baidu Button BEGIN --><script type="text/javascript" id="bdshare_js" data="type=tools&uid=1536434"></script><script type="text/javascript" id="bdshell_js"></script><script type="text/javascript">
document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)
</script><!-- Baidu Button END --> func1();
else
func2();
进行宏代码展开后,成为:
if (cond)
if (1)
for (int i = 0; i
func1();
else
func2();
这个结果显然不能符合我们的原意。这里func2();语句永远得不到执行机会。
2)模板参数类型如果不出现在参数列表中,则不能作为返回值类型。
由于编译器的缺陷,VC++ 6.0不支持以下这种用法:
template <class t1 class t2></class>
T1 func(T2 arg)
{
T1 var;
... // 处理var过程
return var;
}
void test()
{
int result1 = func<int>(1);</int>
double result2 = func<double>(2);</double>
};
很抱歉,这种用法VC++ 6.0不支持。让人恼火的是,VC++ 6.0编译时不会提示错误,但是生成的执行代码却很成问题。
究其原因,是因为VC++ 6.0的template技术是在编译器的较高层次做的,真正的编译器核心并不考虑模板。以上面的代码为例,对编译器核心来说,只是有两个重载函数而已:
int func(int arg);
double func(int arg);
如果是普通情况,只是返回值不同的函数,是不能同时存在的,编译器应该认为这是一个错误。但是很在模板情况下,这两个函数被简单认为是同一个函数。因为VC++ 6.0会为每个函数根据它的:
1)所在的namespace;
2)所在的类的类名(如果是成员函数);
3)函数名;
4)函数调用方式(cdecl、stdcall还是fastcall);
5)所有参数的类型;
而生成一个唯一标识该函数的函数名。这个过程叫Name Mangling,是所有C++编译器都要进行的工作。而另一个背景是,很多C++编译器生成的目标文件(.obj文件)有一些和模板相关的特殊信息,包括也标识了某个函数是否模板函数。这是因为一个模板函数在多个源文件(.cpp文件)中被调用的话,这个模板函数就会在这些源文件编译生成的目标文件(.obj文件)中都定义(definition)一份。为了支持模板,link程序显然必须知道这个函数是模板函数,从而随意选择一个定义(丢弃其余的定义),而不是报符号重复定义错误。
因为函数名、参数列表等完全一致,所以这两个函数Name Mangling后生成的名字是一样的,并且,它们都被标识为这是模板函数。从而,link程序在工作的时候,简单地将其中一个函数定义给抛弃了。
那么,如果我们非要提供上述的func函数,怎么办?我们来点花招:
template <class t1></class>
class func
{
private:
T1 var;
public:
template <class t2></class>
func(T2 arg)
{
... // 处理var过程
}
operator T1() const
{
return var;
}
};
我们再来使用func这个“函数”:
void test()
{
int result1 = func<int>(1);</int>
double result2 = func<double>(2);</double>
};
呵呵,你会发现,它还真象是你期望的正常工作。
3)仿真VC++提供的关键字__uuidof。
这个技巧不是针对VC++ 6.0缺陷的,而是针对VC++扩展语法的。这个技巧的来由,是为了某些希望有一天有可能要脱离Visual C++环境进行开发的人员。为了脱离VC++,你需要谨慎使用它的所有扩展语法。例如本文讨论的__uuidof。我们先来看看一个例子:
class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Class;
struct __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BB")) Interface;
void test()
{
CLSID clsid = __uuidof(Class);
IID iid = __uuidof(Interface);
...
}
这比起你以前定义uuid的方法简单多了吧?可惜,这样好用的东西,它只在VC++中提供。不过没有关系,我们这里介绍一个技巧,可以让你在几乎所有C++编译器中都可以这样方便的使用__uuidof。这里没有说是所有,是因为我们使用了模板特化技术,可能存在一些比较“古老”的C++编译器,不支持该特性。
也许你已经迫不及待了。好,让我们来看看:
#include <string></string>
#include <cassert></cassert>
inline
STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz)
{
HRESULT hr;
GUID guid;
if (lpsz[0] == '{')
{
hr = CLSIDFromString(lpsz, &guid);
}
else
{
std::basic_string<olechar> strGuid;</olechar>
strGuid.append(1, '{');
strGuid.append(lpsz);
strGuid.append(1, '}');
hr = CLSIDFromString((LPOLESTR)strGuid.c_str(), &guid);
}
assert(hr == S_OK);
return guid;
}
template <class class></class>
struct _UuidTraits {
};
#define _DEFINE_UUID(Class, uuid) /
template /
struct _UuidTraits<class> {/</class>
static const GUID& Guid() {/
static GUID guid = GUIDFromString(L ## uuid); /
return guid;/
}/
}
#define __uuidof(Class) _UuidTraits<class>::Guid()</class>
#define DEFINE_CLSID(Class, guid) /
class Class;/
_DEFINE_UUID(Class, guid)
#define DEFINE_IID(Interface, iid) /
struct Interface;/
_DEFINE_UUID(Interface, iid)
这样一来,就已经模拟出一个__uuidof关键字。我们可以很方便进行uuid的定义。举例如下:
DEFINE_CLSID(Class, "{B372C9F6-1959-4650-960D-73F20CD479BA}");
DEFINE_IID(Interface, "{B372C9F6-1959-4650-960D-73F20CD479BB}");
void test()
{
CLSID clsid = __uuidof(Class);
IID iid = __uuidof(Interface);
...
}
在VC++中,为了与其他编译器以相同的方式来进行uuid的定义,我们不直接使用__declspec(uuid),而是也定义DEFINE_CLSID, DEFINE_IID宏:
#define DEFINE_CLSID(Class, clsid) /
class __declspec(uuid(clsid)) Class
#define DEFINE_IID(Interface, iid) /
struct __declspec(uuid(iid)) Interface
这样一来,我们已经在所有包含VC++在内的支持模板特化技术的编译器中,提供了__uuidof关键字。通过它可以进一步简化你在C++语言中实现COM组件的代价。
附注:关于本文使用的C++模板的特化技术,详细请参阅C++文法方面的书籍,例如《C++ Primer》。其实这个技巧在C++标准库——STL中有一个专门的名字:traits(萃取),你可以在很多介绍STL的书籍中见到相关的介绍。
<script type="text/javascript">
new Ad(4, 'ad_cen');
</script>
<script type="text/javascript">
var fileName = '2239178';
var commentscount = 0;
var islock = false
</script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/comment.js"></script>核心技术类目
全部主题
Hadoop
AWS
移动游戏
Java
Android
iOS
Swift
智能硬件
Docker
OpenStack
VPN
Spark
ERP
IE10
Eclipse
CRM
JavaScript
数据库
Ubuntu
NFC
WAP
jQuery
BI
HTML5
Spring
Apache
.NET
API
HTML
SDK
IIS
Fedora
XML
LBS
Unity
Splashtop
UML
components
Windows Mobile
Rails
QEMU
KDE
Cassandra
CloudStack
FTC
coremail
OPhone
CouchBase
云计算
iOS6
Rackspace
Web App
SpringSide
Maemo
Compuware
大数据
aptech
Perl
Tornado
Ruby
Hibernate
ThinkPHP
HBase
Pure
Solr
Angular
Cloud Foundry
Redis
Scala
Django
Bootstrap
- 个人资料
- 访问:1381121次
- 积分:83466分
- 排名:第4名
- 原创:7468篇
- 转载:0篇
- 译文:0篇
- 评论:81条
- 文章存档
-
阅读排行
- GB2312汉字拼音对照表(7397)
- 手机"用户界面和多媒体"版面有价值问题整理[j2medev.com][0406更新](7255)
- [SP]梦网masterSP模式下的sp生存(4871)
- [转]FTP搜索引擎的设计与实现(优化版)(4380)
- [dotNET]“ThreadPool 对象中没有足够的自由线程来完成操作”的现象和解决办法(4011)
- 《ASP.NET 2.0应用开发技术》9月份出版发行(3978)
- [收藏]C++大师Stan Lippman:我对中国程序员的忠告(3232)
- WinCVS中文版及中文使用手册(3061)
- zlib 与 libpng 的配置与使用 part 3 libpng的安装与生成PNG图片(3028)
- [收藏]深入浅出的《网络socket编程指南》(3028)
- 评论排行
- 推荐文章
- 最新评论
-
[C#]I/O完成端口的实现
allenltiverson: 有你这么2的人么。。。
-
创建一个MDB文件
liuqingyunwoniu: 额 楼主怎么复制这么多
-
字符集之间转换(UTF-8,UNICODE,Gb2312)
lvron: 确定是你的原创吗?
-
[收藏]C++大师Stan Lippman:我对中国程序员的忠告
kongguisheng: 重复排了85次?
-
[USTC]中科大备忘录
xiaowaiwaia: 作者想表达什么意思 没看懂
-
C++不是万能的
dujianwei110120: 这个写的相当不错,也很专业的哦!
-
[USTC]中科大备忘录
Sense_the_World: 你妹的..
-
[人物]USTC十大IT精英
wave_hack: 就几个人,有必要贴几遍吗?
-
我对SOA的反思:SOA架构的本质
JG_jiangguo: 复制这么多是为了凑字数么?
-
--=== 让你的程序开始说话(在VB中使用文字朗读引擎(TTS)技术)===--
dandanzmc: voicetext 1.0 type libary 丢失怎么办啊??谢谢、、、
相关推荐
VC++6.0简体中文版本,支持win7提示兼容问题忽略就行。 此前装过别的版本,但win7大多装不上,有的能装上但过程太繁琐。 别的版本有几百兆,而这只有30来兆,而且可直接安装运行,对于专业人士来说此版本功能过于简单...
使用VC++6.0,编写的MFC程序,实现正弦曲线的绘制,包括横纵坐标轴的绘制。
可以在win7上使用的VC++6.0,包含英文版
用VC++6.0打开工程文件dsw即可查看和编译代码。。。。。。
编者 求是科技 王正军 《VC++6.0从入门到精通》源码,
VC++6.0绿色版,Win764位下可以正常运行,解决安装之苦。
vc++6.0下开发的仓库管理系统,采用ADO操作数据库,使用数据库为ACCE-vc 6.0's warehouse management system using ADO operational database, using the database to ACCE
VC++6.0 小游戏之推箱子采用VC++6.0开发,并通过编译运行,能够玩
Win32环境下基于VC++6.0串口通信编程方法
VC++6.0快捷键大全 为VC++6.0快捷键大全.txt 方便参阅
VC++6.0小游戏之俄罗斯方块源代码采用VC++6.0开发,已通过编译能够正常运行使用
windows 32位 vc++ 6.0 sp6补丁包
VC++6.0 基于MFC的windows资源管理器风格单文档应用程序 学生管理系统实现增删改查学生信息
VC++6.0小游戏之扫雷源代码是采用VC++6.0开发编译的小游戏扫雷,可以玩
vc++6.0入门教程(PDF编辑版)整理.pdf
install shield for vc++6.0 从光盘拷下来的,因为太大所以分成两个,只要解压后放在一个文件夹就可以安装了,不收分。保证可安装。
VC++6.0 开发宝典 VC++6.0 开发宝典 VC++6.0 开发宝典
VC++ 6.0 音乐播放器VC++ 6.0 音乐播放器VC++ 6.0 音乐播放器VC++ 6.0 音乐播放器VC++ 6.0 音乐播放器
VC++6.0 界面美化包,已编绎 直接 用就可以。 我自己放在这里备份用的。省得找不到,又要编绎一次。
VC++6.0编译通过的读写CSV文件的代码及实例 在VC++6.0中编译通过,实测可用 通用性很不错 包含CSV读取的实例