断言宏?

时间:2008-05-14 10:37:18   来源:论坛整理  作者:  编辑:chinaitzhe
看书时,有一个练习,但答案看不懂,麻烦高手解释一下。

问题:
每当使用ASSERT,宏__FILE__就产生一个唯一的文件名字符串。这就是说,假如
在同一个文件中使用了73 个断言,编译程序就会产生73 个完全相同的文件名字符
串。怎样实现ASSERT 宏,才能使文件名字符串在每个文件中只被定义一次?

答:
假如你的编译程序支持一个这样的开关,它通知编译程序将所有相同的字符串分配
在同一个位置上,那么最简单的办法就是不要这个开关。假如答应这个选择,你的程序即或
声明了73 个文件名的副本,编译程序只分配一个字符串。这种方法的缺点是,它不仅“覆
盖”了断言字符串,还将源文件中所有等长的字符串都“覆盖”了,只是不希望有的多余行
为。
另一种办法是改变ASSERT 宏的实现,有意识的只引用整个文件中相同文件名的字符串。
唯一的困难是如何建立文件名的字符串,但是即使这不成问题,你也应该把实现细节隐藏在
163
一个新的ASSERTFILE 宏中,这个宏只在源程序文件的开始处使用一次:
#include <stdio.h>
……
#include <debug.h>
ASSERTFILE( __FILE__ ) /* 加*/
……
void* memcpy( void* pvTo, void* pvFrom, size_t size )
{
byte* pbTo = (byte*)pvTo;
byte* pbFrom = (byte*)pvFrom;
ASSERT( pvTo != NULL && pvFrom != NULL ); /* 没有变更*/
……
下面是实现ASSERTFILE 宏的代码和相应的ASSERT 版本。
#ifdef DEBUG
#define ASSERTFILE(str) static char strAssertFile[] = str;
#define ASSERT(f) \
if( f ) \
NULL \
else \
_Assert( strAssertFile, _LINE_ )
#else
#define ASSERTFILE(str)
#define ASSERT(f) NULL
#endif
使用该版本的ASSERT,可以获得大量的存储空间。例如,本书的测试应用程序很小,
但是使用上面新给的代码,这些程序可以节省3K 的数据空间。

网友回复:假如不是DEBUG,则
#define ASSERTFILE(str)
#define ASSERT(f) NULL

否则,
#define ASSERTFILE(str) static char strAssertFile[] = str; 定义一个静态变量strAssertFile
#define ASSERT(f) \ 定义宏ASSERT
if( f ) \假如f不为空,则啥也不做
NULL \
else \
_Assert( strAssertFile, _LINE_ ) 否则,执行这个
网友回复:“这些程序可以节省3K 的数据空间”请问是如何节省空间的?
static char strAssertFile[] = str;不会引起重复定义吗?
网友回复:这本书看着很眼熟,是学习c语言的一本好书,其中部分内容对c 同样有意义。

答案的第一种方式是靠编译器参数,大多数编译器都提供一个功能,就是将所有相同的字符串常量合并为一个。
第二种方式是在每个文件中定义一个static char strAssertFile[]存储本文件的名称,在vc6中也是这种方式存的,不过这本书虽说是MS但是跟vc6还是有细节上的差异的。
网友回复:收藏
网友回复:
引用 2 楼 clxye 的回复:
“这些程序可以节省3K 的数据空间”请问是如何节省空间的?
static char strAssertFile[] = str;不会引起重复定义吗?


如同你在多个地方写了
char * pchar="hello";

"hello"就在多个地方保存了多个,这不是浪费么
网友回复:下面的是预编译,在编译之前的工作,所以节省空间了
网友回复:
引用 2 楼 clxye 的回复:
“这些程序可以节省3K 的数据空间”请问是如何节省空间的?
static char strAssertFile[] = str;不会引起重复定义吗?


ASSERTFILE( __FILE__ )仅在文件开头书写一次,因此不会重复定义。
定义了strAssertFile之后所有的ASSERT都使用strAssertFile存储的文件名而不是使用__FILE__生成的字符串常量,因此在整个文件中代表文件名的字符串常量只出现一次就可以了,就节省了空间了。
网友回复:呵呵,感谢大家,只有Maxwell的解释我看明白了。

假如你的编译程序支持一个这样的开关,它通知编译程序将所有相同的字符串分配
在同一个位置上,那么最简单的办法就是不要这个开关。假如答应这个选择,你的程序即或
声明了73 个文件名的副本,编译程序只分配一个字符串。这种方法的缺点是,它不仅“覆
盖”了断言字符串,还将源文件中所有等长的字符串都“覆盖”了,只是不希望有的多余行
为。

Maxwell解释 "答案的第一种方式是靠编译器参数,大多数编译器都提供一个功能,就是将所有相同的字符串常量合并为一个。 "

这个编译器参数和实现我不太了解。我想是不是把出现的所有__FILE__都合并成一个字符串,这也应该是Maxwell的解释。但是书中的解释说不要这个开关,我感觉这时应该是需要才对啊。他说假如答应这个选择,将会声明73个副本,我感觉似乎应该是假如禁止这个选择才会这样。“这种方法的缺点是,它不仅“覆盖了断言字符串,还将源文件中所有等长的字符串都“覆盖”了,只是不希望有的多余行为。 ”这句话又该如何理解呢?

谢谢!
网友回复:说不要似乎是有点问题,不过记得这本书里小错误还是不少,书也不在手头,不知道当时我是否加了什么注释没有。另外,现在看这个感觉可能是电子版,说不定是抄的时候抄错了。

C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/



那么最简单的办法就是使用这个开关。假如答应这个选择,你的程序即使声明了73 个文件名的副本,编译程序只分配一个字符串。


应该是这样才对。

C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/



这种方法的缺点是,它不仅“覆盖了断言字符串,还将源文件中所有等长的字符串都“覆盖”了,只是不希望有的多余行为。


看了这个我更相信你是看的电子版了。这句的意思是说这个开关会将所有长度相同的字符串常量合并为一个,这一点我记不清楚了,也许过去某个编译器是这么处理的,以减少合并时比较的工作量。
网友回复:找到一些痕迹:
http://www.dotblogs.com.tw/dllee/archive/2008/04/29/3604.aspx

建议楼主换本书吧。
这些文字写在十多年前,咱不能否认这些东西在当时的意义。
不过关于计算机,十多年前的东西怎么也算是古董了吧。
1. 3K的数据空间,算了吧。
2. 没有看“出声明了73 个文件名的副本,编译程序只分配一个字符串。”有什么问题;
即使“它不仅"覆盖"了断言字符串,还将源文件中所有等长的字符串都"覆盖"了”
网友回复:有些东西不能只看年份,我至今认为这本书是想成为c语言高手必看的书。
网友回复:
引用 11 楼 Maxwell 的回复:
有些东西不能只看年份,我至今认为这本书是想成为c语言高手必看的书。

很赞同这个观点。
不过应该要有取舍。
就楼主提到问题本身来说,这本书上的描述真的过时了。
至于是不是必看的书,也许不同的人有不同的选择。
俺没觉得这是本必看的书,至少在现在不是了。

网友回复:Good.呵呵,Maxwell猜的不错,我的确看的是电子版的。
谢谢!!
关键字:断言,

文章评论

共有 0 位网友发表了评论 此处只显示部分留言 点击查看完整评论页面