Archive for April, 2007
Judith
That I’ll never ever choose to be
Oh so many ways for me to show you
How the savior has abandoned you
F*ck your God
Your Lord and your Christ
He did this
Took all you had and
Left you this way
Still you pray, you never stray
Never taste of the fruit
You never thought to question why
It’s not like you killed someone
It’s not like you drove a hateful spear into his side
Praise the one who left you
Broken down and paralyzed
He did it all for you
He did it all for you
Oh so many many ways for me to show you
How your dogma has abandoned you
Pray to your Christ, to your god
Never taste of the fruit
Never stray, never break
Never—choke on a lie
Even though he’s the one who did this to you
You never thought to question why
Not like you killed someone
It’s Not like you drove a spiteful spear into his side
Talk to Jesus Christ
As if he knows the reasons why
He did it all for you
Did it all for you
He did it all for you
Sooner or Later we all die
c++的几种cast zz
Posted by xiaokucha in Programming on April 12, 2007
先看看这篇文章,然后说一下问题:
一共四种cast。1、static_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,反过来也支持,但会给出编译警告,它作用最类似C风格的“强制转换”,一般来说可认为它是安全的;2、dynamic_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和static_cast不同,反过来它就不支持了,会导致编译错误,这种转换是最安全的转换;3、reinterpret_cast,支持任何转换,但仅仅是如它的名字所描述的那样“重解释”而已,不会对指针的值进行任何调整,用它完全可以做到“指鹿为马”,但很明显,它是最不安全的转换,使用它的时候,你得头脑清醒,知道自己在干什么;4、const_cast,这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。
这样回答即使得不了满分,拿个八九十分应该也没问题了,我后来还专门写了些测试程序来验证过,对于第一第二第三种转换都没什么问题,而const_cast却似乎不能正常工作,代码如下:
int main(int argc, char* argv[]) { const int ic=100; const_cast<int &>(ic)=200; printf("%dn", ic); return 0; } |
结果不是我期待的200,而是100,我一开始以为这是由于优化选项的问题,于是调整编译器选项,全部不优化,但还是一样的结果,我开始怀疑这是VC++的bug,于是使用Linux的g++来编译,结果一样,看来这和编译器没有关系,那我究竟做错了哪里呢?或者我对const_cast理解错了呢?我开始改进我的代码,我尝试不同的类型:
class CTest { public: CTest(int i){m_val = i;printf("construction [%d]n", m_val);}; ~CTest(){printf("destructionn");}; void SelfAdd(){m_val++;}; int m_val; };
int main(int argc, char* argv[]) { const CTest test(1000); CTest test2(1050); const_cast<CTest &>(test)= test2; printf("%dn", test.m_val); return 0; } |
这次总算得到了我想要得到结果,打印出了1050,说明const_cast并没有问题,但前一个程序为什么不能正常工作?我继续尝试了不同的类型,比如char,short,float,double等,发现了规律,凡是对结构体或类进行这个转换,都是成功的,但对char,short等基本类型的转换都没有成功。我进一步改进代码,为了查看它们的值是否真的已经被修改,我使用了指针:
int main(int argc, char* argv[]) { const int ic = 100; const int *pc=⁣ const_cast<int &>(ic)++; printf("%d,%dn", ic, *pc); return 0; } |
这次打印出来的结果是“100,101”,这就说明常量ic的值确实已经被改变了,但为什么直接打印ic就得不到正确的结果?那估计还是前边想到的“优化”的原因,可我一再确认我并没有使用优化编译选项,而且g++的表现也如此。看来只好使用最后一招了,直接查看printf究竟做了些什么,在printf处设置断点,调试程序,然后打开disassembly视图查看反汇编代码,一切真相大白。
原来虽然我没有使用优化,但系统还是对ic这个const进行了预编译般的替换,将它替换成“64h”(十六进制的64就是十进制的100),这究竟是不是C++的规范?我不知道,但我肯定这不是一般用户想要的结果,对我来说,算是个C++的bug吧。通过解决这个问题,我也学会了些东西,如果以后遇到类似这种表面上再显浅不过,但就是不能正常工作的代码片断,要学会查看反汇编代码,也许一切问题迎刃而解,另外使用const_cast的时候应该注意些什么东西,嗯,自己思考一下吧。Java没有const_cast,很多语言都没有,(我只知道C++有)既然已经被定义为常量,就是不希望它被改变,但现在又允许你改变它,这不是很可笑吗?但难道它不是C++强大又灵活的又一体现吗?不过话说回来要看你怎么用了。
好了,文章说的很清楚,const_cast可以修改常量,可以修改类,不过这里主要出现的问题就是编译器的处理。
试想如果这样写代码:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const volatile int ic = 100;//volatile
const volatile int *pc=⁣
const_cast<int &>(ic)++;
printf("%d,%dn", ic, *pc);
system("pause");
return 0;
}
程序就会输出101,101,因为volatile以后,跳过了编译器指定寄存器中的内容,直接取的内存中数值,所以文章中之所以总会出现ic原来的值,是因为寄存器中值的假象。手头没有vc++不知道debug模式下,const_cast之后,printf会不会调用内存值。而对于类,个人认为类每次取的值不可能在寄存器中,应该是每次取一次内存,所以不会出现假象
经典语录zz from lqqm
上中学的时候,会踢球、有女生暗恋的是牛*B的,我是傻*B的;
上大学的时候,学习成绩好、个高人帅的是牛*B的,我是傻*B的;
参加工作以后,有家庭背景、北京户口的是牛*B的,我是傻*B的;
转眼谈婚论嫁,有车有房、存折后边零多的是牛*B的,我还是傻*B的;
这才发现斗转星移,沧海桑田,牛*B的定义一直在变,而我却一直是傻*B的……(水木社区)
21.割下JJ敬神——既疼了自己,又得罪了神~(天涯宁夏 作者:梦回大漠)
51.刻苦用功,逃离华工!(华南木棉 作者:ch_k_f)
huawei最后一道小题
Posted by xiaokucha in Programming on April 7, 2007
char tdata;
struct tnode *lchild,*rchild;
}tnode,*tree;
typedef struct fnode{
char fdata;
struct fnode *firstchild,*nextsibling;
}fnode,*forest;
if(a){
if(!(b=(tnode *)malloc(sizeof(tnode))))
exit(0);
b->tdata=a->fdata;
foresttotree(a->firstchild,b->lchild);
foresttotree(a->nextsibling,b->rchild);
}
}
zz
(比目鱼博客:http://www.bimuyu.com/blog/)
广告词:(手举一颗钉子)除了锤子,不向任何人低头!
广告词:粉丝就应该这样:好痴(吃)!好痴(吃)!
广告词:(手持一把炒勺)有人说我天天炒,其实全靠工具好!
广告词:(东北口音)你太有柴了!
广告词:(站在猪圈前,吼叫)你不是一个人!!(停顿片刻)你是一只猪!!
广告词:很快乐,不难生!
linus写的,貌似
Posted by xiaokucha in Programming on April 6, 2007
2 * linux/lib/string.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 /*
8 * stupid library routines.. The optimized versions should generally be found
9 * as inline code in <asm-xx/string.h>
10 *
11 * These are buggy as well..
12 */
13
14 #include <linux/types.h>
15
16 char * ___strtok = NULL;
17
18 char * strcpy(char * dest,const char *src)
19 {
20 char *tmp = dest;
21
22 while ((*dest++ = *src++) != ”)
23 /* nothing */;
24 return tmp;
25 }
26
27 char * strncpy(char * dest,const char *src,size_t count)
28 {
29 char *tmp = dest;
30
31 while (count– && (*dest++ = *src++) != ”)
32 /* nothing */;
33
34 return tmp;
35 }
36
37 char * strcat(char * dest, const char * src)
38 {
39 char *tmp = dest;
40
41 while (*dest)
42 dest++;
43 while ((*dest++ = *src++) != ”)
44 ;
45
46 return tmp;
47 }
48
49 char * strncat(char *dest, const char *src, size_t count)
50 {
51 char *tmp = dest;
52
53 if (count) {
54 while (*dest)
55 dest++;
56 while ((*dest++ = *src++)) {
57 if (–count == 0)
58 break;
59 }
60 }
61
62 return tmp;
63 }
64
65 int strcmp(const char * cs,const char * ct)
66 {
67 register signed char __res;
68
69 while (1) {
70 if ((__res = *cs – *ct++) != 0 || !*cs++)
71 break;
72 }
73
74 return __res;
75 }
76
77 int strncmp(const char * cs,const char * ct,size_t count)
78 {
79 register signed char __res = 0;
80
81 while (count) {
82 if ((__res = *cs – *ct++) != 0 || !*cs++)
83 break;
84 count–;
85 }
86
87 return __res;
88 }
89
90 char * strchr(const char * s,char c)
91 {
92 for(; *s != c; ++s)
93 if (*s == ”)
94 return NULL;
95 return (char *) s;
96 }
97
98 size_t strlen(const char * s)
99 {
100 const char *sc;
101
102 for (sc = s; *sc != ”; ++sc)
103 /* nothing */;
104 return sc – s;
105 }
106
107 size_t strnlen(const char * s, size_t count)
108 {
109 const char *sc;
110
111 for (sc = s; *sc != ” && count–; ++sc)
112 /* nothing */;
113 return sc – s;
114 }
115
116 size_t strspn(const char *s, const char *accept)
117 {
118 const char *p;
119 const char *a;
120 size_t count = 0;
121
122 for (p = s; *p != ”; ++p) {
123 for (a = accept; *a != ”; ++a) {
124 if (*p == *a)
125 break;
126 }
127 if (*a == ”)
128 return count;
129 ++count;
130 }
131
132 return count;
133 }
134
135 char * strpbrk(const char * cs,const char * ct)
136 {
137 const char *sc1,*sc2;
138
139 for( sc1 = cs; *sc1 != ”; ++sc1) {
140 for( sc2 = ct; *sc2 != ”; ++sc2) {
141 if (*sc1 == *sc2)
142 return (char *) sc1;
143 }
144 }
145 return NULL;
146 }
147
148 char * strtok(char * s,const char * ct)
149 {
150 char *sbegin, *send;
151
152 sbegin = s ? s : ___strtok;
153 if (!sbegin) {
154 return NULL;
155 }
156 sbegin += strspn(sbegin,ct);
157 if (*sbegin == ”) {
158 ___strtok = NULL;
159 return( NULL );
160 }
161 send = strpbrk( sbegin, ct);
162 if (send && *send != ”)
163 *send++ = ”;
164 ___strtok = send;
165 return (sbegin);
166 }
167
168 void * memset(void * s,char c,size_t count)
169 {
170 char *xs = (char *) s;
171
172 while (count–)
173 *xs++ = c;
174
175 return s;
176 }
177
178 char * bcopy(const char * src, char * dest, int count)
179 {
180 char *tmp = dest;
181
182 while (count–)
183 *tmp++ = *src++;
184
185 return dest;
186 }
187
188 void * memcpy(void * dest,const void *src,size_t count)
189 {
190 char *tmp = (char *) dest, *s = (char *) src;
191
192 while (count–)
193 *tmp++ = *s++;
194
195 return dest;
196 }
197
198 void * memmove(void * dest,const void *src,size_t count)
199 {
200 char *tmp, *s;
201
202 if (dest <= src) {
203 tmp = (char *) dest;
204 s = (char *) src;
205 while (count–)
206 *tmp++ = *s++;
207 }
208 else {
209 tmp = (char *) dest + count;
210 s = (char *) src + count;
211 while (count–)
212 *–tmp = *–s;
213 }
214
215 return dest;
216 }
217
218 int memcmp(const void * cs,const void * ct,size_t count)
219 {
220 const unsigned char *su1, *su2;
221 signed char res = 0;
222
223 for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count–)
224 if ((res = *su1 – *su2) != 0)
225 break;
226 return res;
227 }
228
229 /*
230 * find the first occurrence of byte ‘c’, or 1 past the area if none
231 */
232 void * memscan(void * addr, unsigned char c, size_t size)
233 {
234 unsigned char * p = (unsigned char *) addr;
235
236 while (size) {
237 if (*p == c)
238 return (void *) p;
239 p++;
240 size–;
241 }
242 return (void *) p;
243 }
memcpy()&memmove()
Posted by xiaokucha in Programming on April 6, 2007
void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst;
/*
* copy from lower addresses to higher addresses
*/
while (count–) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return(ret);
}
void * __cdecl memmove (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst;
if (dst <= src || (char *)dst >= ((char *)src + count)) {
/*
* Non-Overlapping Buffers
* copy from lower addresses to higher addresses
*/
while (count–) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
dst = (char *)dst + count – 1;
src = (char *)src + count – 1;
while (count–) {
*(char *)dst = *(char *)src;
dst = (char *)dst – 1;
src = (char *)src – 1;
}
}
return(ret);
}
今天huawei一个小题,如下:
char *str1="this is a string";
char *str2="this is a string";
memcpy(str1+4,str1,6);
memmove(str2+4,str2,6);
printf("%sn",str1);
printf("%sn",str2);
这段程序在现在的编译器比如dev-c++上compile会报错,就是因为在我以前写的潜规则中提到的char *定义赋值字符串问题,这种写法已经被淘汰了,因为char *现在一般用于定义指针而无内部类型,这里最好用char [20];
然后在tc2上编译了一下,发现自己sb了。。。
结果如下:
thisthisthstring
thisthis istring
不过在dev-c++上面将*改为[]后,发现结果如下
thisthis istring
thisthis istring
主要的问题就是Overlap(内存重叠),上面的CRT代码已经写出来了memcpy和memmove的区别,memcpy是memmove的子集,memmove可以对于重叠的内存操作进行逆序处理。。。memcpy对于重叠的copy会出现非所期望的结果,在copy的同时改变了src的内容,所以对于src,我们强调一定要const。。。根据上述结果可以猜测tc2里面的memcpy和memmove没有强调src的const,而现在的CRT应该是上面所ctrl+v的
对于旧的c标准,我是sb,同时,对于新的标准,这道题sb,以上。
volatile(zz from csdn)
Posted by xiaokucha in Programming on April 3, 2007
void main()
{
int i=10;
int a = i;
mov dword ptr [ebp-4], 50h
}
//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道,来隐式的修改了变量。
int b = i;
printf("i= %dn",b);
}
i = 10
i = 80
i = 10
i = 10
void main()
{
volatile int i=10;
int a = i;
__asm {
mov dword ptr [ebp-4], 50h
}
printf("i= %dn",b);
}
i = 10
i = 32
系统总是在 volatile 对象被请求的那一刻读取其当前值,即使上一条指令从同一对象请求值。而且,该对象的值在赋值时立即写入。
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}