当前位置: 首页 > 编程日记 > 正文

VC++ 6.0的小花招

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 < 100; ++i)
func();
for (int i = 0; i < 100; ++i)
func2();
而下面这段代码应该编译不过:
for (int i = 0; i < 100; ++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 < 100; ++i)
func1();
else
func2();
进行宏代码展开后,成为:
if (cond)
if (1)
for (int i = 0; i < 100; ++i)
func1();
else
func2();
这个结果显然不能符合我们的原意。这里func2();语句永远得不到执行机会。
2)模板参数类型如果不出现在参数列表中,则不能作为返回值类型。
由于编译器的缺陷,VC++ 6.0不支持以下这种用法:
template <class T1, class T2>
T1 func(T2 arg)
{
T1 var;
... // 处理var过程
return var;
}
void test()
{
int result1 = func<int>(1);
double result2 = func<double>(2);
};
很抱歉,这种用法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 func
{
private:
T1 var;
public:
template <class T2>
func(T2 arg)
{
... // 处理var过程
}
operator T1() const
{
return var;
}
};
我们再来使用func这个“函数”:
void test()
{
int result1 = func<int>(1);
double result2 = func<double>(2);
};
呵呵,你会发现,它还真象是你期望的正常工作。
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>
#include <cassert>
inline
STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz)
{
HRESULT hr;
GUID guid;
if (lpsz[0] == '{')
{
hr = CLSIDFromString(lpsz, &guid);
}
else
{
std::basic_string<OLECHAR> strGuid;
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>
struct _UuidTraits {
};
#define _DEFINE_UUID(Class, uuid)                                        \
template <>                                                              \
struct _UuidTraits<Class> {                                              \
static const GUID& Guid() {                                          \
static GUID guid = GUIDFromString(L ## uuid);                    \
return guid;                                                     \
}                                                                    \
}
#define __uuidof(Class)    _UuidTraits<Class>::Guid()
#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的书籍中见到相关的介绍。

相关文章:

【linux】嵌入式中 crontab的使用

0、编辑 执行&#xff1a;crontab -e 执行命令后&#xff0c;将出现一个编辑界面&#xff0c;内容格式如下 Minute Hour Day Month Dayofweek command 分钟 小时 天 月 天每星期 命令 每个字段代表的含义如下&#xff1a; Minute 每个小时的第几分钟执行该任务 Hour 每天的第几…

程序员该怎么做,才能成为coding王者?

每当做编程题目时&#xff0c;大多数人都会靠基本的直觉&#xff0c;遵循一些固定的步骤来有效地解题。不管是有意还是无意&#xff0c;在做编程题目的时你会下意识地遵循一些步骤&#xff0c;在阅读完这篇文章后你就可以将这些步骤和这篇文章联系起来&#xff0c;从而就可以更…

27.3. source code

tar zxvf bandwidthd-2.0.1.tgz cd bandwidthd-2.0.1 ./configure --prefix/srv/bandwidthd-2.0.1 make make install 原文出处&#xff1a;Netkiller 系列 手札 本文作者&#xff1a;陈景峯 转载请与作者联系&#xff0c;同时请务必标明文章原始出处和作者信息及本声明。

WF4.0实战(一):文件审批流程

http://www.cnblogs.com/zhuqil/archive/2010/04/13/DocumentApprovalProcess.html转载于:https://www.cnblogs.com/Little-Li/archive/2010/06/01/1749392.html

AI科技大本营在线公开课大放送(附演讲PPT)

新年新思&#xff01;新一年&#xff0c;每个人的梦想都闪耀着多彩光芒&#xff0c;对于AI领域的每一位学习者和从业者&#xff0c;我们充满渴望&#xff0c;怀揣梦想&#xff0c;心系对技术的不懈追求。AI科技大本营同样也有自己的新年梦想和脚踏实地的规划&#xff0c;比如今…

《微信跳一跳》安卓手机刷分软件搭建及攻略

2019独角兽企业重金招聘Python工程师标准>>> 元旦期间被微信小程序的游戏刷屏幕了。手笨脚笨的我也尝试了下这新出的小玩意&#xff0c;实在话手脚不协调最高仅仅90分&#xff0c;处于做技术的角度&#xff0c;直觉上可以技术上模拟解决&#xff0c;凑好朋友在微信群…

【libevent】libevent库学习总结(一)——基础

libevent库学习总结&#xff08;一&#xff09;——基础 一、基础 1.1、 介绍 Libevent是一个用于开发可伸缩网络服务器的事件通知库。Libevent API提供了一种机制来执行回调函数&#xff0c;当某个特定事件发生在文件描述符上或超时到达之后。此外&#xff0c;Libevent还支…

AS1.0(2.0)中的XML示例

虽然Flash早就升级为AS3.0&#xff0c;但是FMS的服务端编程依然仅支持AS1.0(2.0)&#xff0c;服务端与.net通讯的最简单方式莫过于请求一个RESTful的webService或wcf&#xff0c;通过它们返回的xml来获取数据。 var _xml:XML new XML("<ArrayOfstring xmlns\"htt…

【Qt】Qt发布可执行程序(打包依赖库)

Qt发布可执行程序&#xff08;打包依赖库&#xff09; 0、编译出可执行文件 如&#xff1a;xxx.exe 1、将xxx.exe拷贝到一个目录下面 2、启动Qt终端交互界面程序 如&#xff1a;Qt 5.6 for Desktop&#xff08;MinGW&#xff09; 3、进入xxx.exe所在的目录 4、执行命令…

小编说之“常见问题答疑”

2019独角兽企业重金招聘Python工程师标准>>> 关于前嗅Forespider爬虫的常见问题答疑 奋战在一线为客户答疑的狗蛋儿给小编提供了很多客户经常会问到的问题的素材&#xff0c;小编帮大家整理了一些&#xff0c;快来看看是不是都用的上吧&#xff01; 一、采集预览没有…

给AI开发者的新年礼物,技术公开课大放送(附演讲PPT)

各位AI科技大本营的伙伴大家好&#xff0c;营长携编辑组的全体成员给大家拜年了&#xff01; 新年新思&#xff01;新一年&#xff0c;每个人的梦想都闪耀着多彩光芒&#xff0c;对于AI领域的每一位学习者和从业者&#xff0c;我们充满渴望&#xff0c;怀揣梦想&#xff0c;心系…

通用权限管理组件使用说明书V3.0 错误校正 感谢自由软件职业者Helper(767870484)...

有时候&#xff0c;真想做个像样的东西出来&#xff0c;但是往往各方面的能力都不够&#xff0c;这么多人&#xff0c;Helper&#xff08;767870484&#xff09;仔细认真的阅读了这个帮助手册、并给给于了指正&#xff0c;在这里非常感谢&#xff0c;你的劳动成果已经被通用权限…

Reddit欲融资3亿美元,由腾讯领投

整理 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;AI科技大本营消息&#xff0c;据 TechCrunch 报道&#xff0c;多个信源透露&#xff0c;美国社交网站 Reddit 将融资 1.5 亿到 3 亿美元&#xff0c;D 轮融资将由中国科技巨头腾讯公司领投&#xff0c;投前…

【libevent】libevent库学习总结(二)——编程步骤

一、libevent编程步骤 0、分配并初始化event_base&#xff0c;两种方法 0.1 event_base_new&#xff1a;线程安全&#xff0c;代替event_init&#xff1b; 0.2 event_init&#xff1a;线程不安全&#xff0c;不推荐使用&#xff0c;仅仅是为了向后兼容 1、创建event&#xf…

HP交换机配置命令

1.命名hostname 7-West-4F-2510 2.设置管理IPvlan 1ip address 192.168.41.123 255.255.255.03.修改支持的默认vlan数max-vlans 64max-vlans //修改vlan的数量&#xff0c;默认只有8个&#xff0c;修改后需重启后才可生效4.重启reload //重启交换机5.配置v…

【Qt】Qt程序编译成功,执行时报错:程序异常结束,crashed

【Qt】Qt程序编译成功&#xff0c;执行时报错&#xff1a;程序异常结束&#xff0c;crashed 错误打印信息 Starting E:*exe… 程序异常结束。 E:*.exe crashed. 原因 使用到外部库&#xff0c;编译时&#xff0c;指定了库连接&#xff0c;但是在程序运行时找不到库&#xf…

近900000条if-then关系图谱,让神经网络“懂”常识推理

编译整理 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;“神经网络能学习日常事件的常识推理吗&#xff1f;能&#xff0c;如果在 ATOMIC 上训练的话。”ATOMIC&#xff08;原子&#xff09; 是一个机器常识图集&#xff0c;一个用自然语言建立的 870, 000 个…

weex 阶段总结

新年伊始&#xff0c;回顾过去的一年&#xff0c;收获很多&#xff0c;之前一直在研究weex&#xff0c;说心里话感觉心好累&#xff0c;官方文档不全&#xff0c;社区不活跃&#xff0c;遇到很多坑&#xff0c;官方发布的版本有时都有坑&#xff0c;搞得我都不敢更新版本了。 但…

DOS批处理高级教程精选(六)

为什么80%的码农都做不了架构师&#xff1f;>>> 第五章 set命令详解 很久没发贴了,今天来写点讲BAT的新手教学贴! 在上一贴中我简单的介绍了一下SET设置自定义变量的作用,现在我来具体讲一下set的其他功能. 一、用set命令设置自定义变量 显示、设置或删除 cmd.exe …

8.11. Migrating MySQL Data into Elasticsearch using logstash

https://www.elastic.co/guide/en/logstash/current/plugins-inputs-jdbc.html 8.11.1. 安装 logstash 安装 JDBC 驱动 和 Logstash curl -s https://raw.githubusercontent.com/oscm/shell/master/database/mysql/5.7/mysql-connector-java.sh | bash curl -s https://ra…

佩奇扑街、外星人疯狂!Python 告诉你大年初二应该看哪部电影

作者 | 罗昭成责编 | 唐小引转载自 CSDN资讯&#xff08;ID&#xff1a;CSDNnews&#xff09;引言2019 年 1 月&#xff0c;《啥是佩奇》短片在互联网快速传播&#xff0c;各大社交平台形成刷屏之势。不到 24 小时&#xff0c;官博发出的视频已经收获 2800 万次观看&#xff0c…

【POCO】POCO学习总结(二)——配置选择

使用方法: configure {options} options总结 –help&#xff1a;打印帮助 –config< config_name> 使用给定配置&#xff0c;在poco-1.7.8p3-all/build/config目录下&#xff0c;可以在对应的配置文件中修改编译工具的路径和名字&#xff0c;编译时的选项等。 AIX Darw…

告别排队!用Python定时自动挂号和快捷查询化验报告

作者 | 阿文来源 | 程序人生&#xff08;ID: coder_life&#xff09;我什么要做这个事情去年单位体检查出问题来&#xff0c;经过穿刺手术确诊是个慢性肾脏病2期&#xff0c; IGA 肾病三期&#xff0c;可能大家对于这个病并不是很了解&#xff0c;但是另外一个词可能大家都听过…

【POCO】POCO学习总结(三)——交叉编译

最小功能编译 编译选项&#xff1a;–minimal &#xff1a;只构建XML, JSON, 工具 and 网络 1 修改配置文件 $ vi poco-1.7.8p3-all/build/config/ARM-Linux13 LINKMODE ? SHARED 14 TOOL ? arm-linux 15 POCO_TARGET_OSNAME Linux 16 POCO_TARGET_OSARCH ? armv7l 主要…

转:入侵网站必备-sql server

来源&#xff1a;http://www.bitscn.com/plus/view.php?aid28692 1.判断有无注入点 ; and 11 and 12 2.猜表一般的表的名称无非是admin adminuser user pass password 等.. and 0(select count(*) from *) and 0(select count(*) from admin) ---判断是否存在admin这张表 3.猜…

27.5. PROCEDURE ANALYSE()

数据列优化 SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]]) 原文出处&#xff1a;Netkiller 系列 手札 本文作者&#xff1a;陈景峯 转载请与作者联系&#xff0c;同时请务必标明文章原始出处和作者信息及本声明。

Linux 日志管理(RHEL7)

日志管理系统和程序的日记本记录系统,程序运行中发生的各种事件通过查看日志,了解及排除故障信息安全控制的依据 内核及系统日志由系统服务rsyslog统一记录/管理日志消息采用文本格式主要记录事件发生的时间,主机,进程,内容常见的日志文件 /var/log/messages 记录内核消息…

汇聚6年思想变迁:知识图谱报告幻灯片大全

本文汇总了中文知识图谱计算会议CCKS报告合集&#xff0c;涵盖从2013年至2018年&#xff0c;共48篇&#xff0c;从中可以看出从Google 2012年推出知识图谱以来&#xff0c;中国学术界及工业界这6年来知识图谱的主流思想变迁。作者 | 刘焕勇来源 | CSDN博客编辑 | apddd项目介绍…

【POCO】POCO学习总结(四)——MinGW编译poco

在window下使用MinGW编译poco 使用MSYS 下载MSYS 官网介绍&#xff1a;http://www.mingw.org/wiki/Getting_Started 官网下载&#xff1a;https://jaist.dl.sourceforge.net/project/mingw/Installer/mingw-get-setup.exe 安装 运行mingw-get-setup.exe&#xff0c;只选择…

辞职之后的思考--激励

本人曾拿过多次奖金&#xff0c;也曾与很多同事沟通过拿奖金的感觉&#xff0c;引发一些思考&#xff0c;这其实也是希望在以后有机会给别人发奖金时做参考之用。   并不是所有人都会有奖金&#xff0c;所以如果我没有奖金其实也没有什么关系&#xff0c;但是&#xff0c;我非…