李迟2011年3月代码积累

上个月积累的代码如下,由于在同一文件中测试多个代码段,因此只好用#if 0 ……#endif的形式来控制了。这次的代码包括:

1、测试函数入栈顺序,入栈顺序依据语言的不同而不同,C语言是从右到左的。从代码的运行结果也可以看出,因为栈帧是往下增长的。

2、从字符串中去除指定字符,这里在csdn帖子中抄来的,原问题是说出现了段错误,因为他使用的不是字符数组。详见代码。

3、移位操作,从http://aggregate.ee.engr.uky.edu/MAGIC/ 抄来的,上面有许多位运算的技巧。那个大小端转换是我自己临时加上去的,因为以前雄心勃勃想研究SD卡时候曾经写过,一时心血来潮也写一下,没想到还没忘记。

4、计算一个数的二进制中包含1的个数,比如7的二进制为0111,则1的个数为3。最后结果和3f相与,一开始不太理解,后来想通了,因为32位的二进制中1的个数最多是32个(似乎是废话)。那个求msb(搞过单片机的应该很熟悉这个东西)的函数中,结果是这样的:比如0x64,二进制为0x0110 0100,最高有效位为0x0100 0000,则结果为0x40。

本文所有代码片段可任意使用而不用告诉作者,当然,作者修改了也不必要告知阁下,而且,由于代码的错误而造成的损失亦与作者无关,不过一起讨论、学习还是可以的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*************************************************


没有main函数
$ gcc rock.c -Wall
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld 返回 1
**************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#if 0
/**************************************************
* 参数入栈测试
编译过程中出现警告:
$ gcc rock.c -Wall
rock.c: 在函数‘main’中:
rock.c:55: 警告:‘t’上的运算结果可能是未定义的
rock.c:57: 警告:‘t’上的运算结果可能是未定义的
rock.c:61: 警告:‘j’上的运算结果可能是未定义的
rock.c:61: 警告:‘j’上的运算结果可能是未定义的
rock.c:51: 警告:未使用的变量‘i’

测试结果:
$ ./a.out 
6 6
6 6
a=6[0xbfaeca30] b=7[0xbfaeca34] c=7[0xbfaeca38]
20
了解过堆栈帧的话,应该知道参数入栈的顺序
**************************************************/

int foo(int a, int b, int c)
{
        printf("a=%d[%p] ",a, &a);
        printf("b=%d[%p] ",b, &b);
        printf("c=%d[%p]/n",c, &c);
        return a+b+c;
}
int main(void)
{
        int i = 3;
        int j = 5;
        int ret;
        int t = 5;
        printf("%d %d/n", ++t, t);
        t = 5;
        printf("%d %d/n", t, ++t);
        //printf("%d %d %d/n", i++, ++i, i);
        //printf("%d %d %d/n", j, ++j, j++);
        //ret = foo(i++, ++i, i);
        ret = foo(j++, ++j, j);
        printf("%d/n", ret);
        return 0;
}
/*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* 参数入栈测试 结束
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
#endif

/*************************************************
* 字符串去除特定字符
* 段错误
运行结果:
$ ./a.out 
Before: abcdabcdabcdefgabcd
After:  abdabdabdefgabd
*************************************************/
#if 0
#include <string.h>
void SqueezeChar(char s[],int c)
{
        int i,j;
        for(i=j=0;i<strlen(s);i++)
                if(s[i]!=c)
                        s[j++]=s[i]; s[j]='/0';
}
int main(void)
{
        //char * org="abcdabcdabcdefgabcd"; // 此处造成段错误
        char org[] = "abcdabcdabcdefgabcd";
        printf("Before:/t%s/n",org);
        SqueezeChar(org,'c');
        printf("After:/t%s/n",org);

        return 0;
}
/*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* 字符串去除特定字符 结束
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
#endif

#if 0
/************************************************
8位、16位、32位平台无符号位反转,如0000ffff --> ffff0000
注:实际中需要注意位数需要一致。比如,不能将unsigned int版本的反转用于unsigned char中。
来自 http://aggregate.ee.engr.uky.edu/MAGIC/
运行结果:
$ ./a.out 
fffe 7fff0000
7f fe00
fe 7f
55aa8977 7789aa55
55aa aa55
*************************************************/
#include <stdio.h>

/* fe --> 7f */
unsigned char reverse8(register unsigned char x)
{
        x = (((x & 0xaa) >> 1) | ((x & 0x5555) << 1));
        x = (((x & 0xcc) >> 2) | ((x & 0x3333) << 2));

        return((x >> 4) | (x << 4));
}

/* 007f --> fe00 */
unsigned short reverse16(register unsigned short x)
{
        x = (((x & 0xaaaa) >> 1) | ((x & 0x5555) << 1));
        x = (((x & 0xcccc) >> 2) | ((x & 0x3333) << 2));
        x = (((x & 0xf0f0) >> 4) | ((x & 0x0f0f) << 4));

        return((x >> 8) | (x << 8));
}

/* fffe --> 7fff0000 */
unsigned int reverse32(register unsigned int x)
{
        x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
        x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
        x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
        x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));

        return((x >> 16) | (x << 16));
}

/* 大小端转换,如 55aa6788 --> 8867aa55 */
unsigned int endian_reverse32(register unsigned int x)
{
        return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24);
}

/* 大小端转换, 如55aa --> aa55 */
unsigned short endian_reverse16(register unsigned short x)
{
        return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);
}

int main(void)
{
        unsigned int i = 65534;
        unsigned int tmp = reverse32(i);
        unsigned short j = 127;
        unsigned short tmp1 = reverse16(j);
        unsigned char k = 254;
        unsigned char tmp2 = reverse8(k);
        
        unsigned int tmp3 = 0x55aa8977;
        unsigned int tmp4 = endian_reverse32(tmp3);
        
        unsigned short tmp5 = 0x55aa;
        unsigned short tmp6 = endian_reverse16(tmp5);
        
        printf("%x %x/n", i, tmp);
        printf("%x %x/n", j, tmp1);
        printf("%x %x/n", k, tmp2);
        printf("%x %x/n", tmp3, tmp4);
        printf("%x %x/n", tmp5, tmp6);
        return 0;
}

/*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* 位反转 结束
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
#endif

#if 0
/*************************************************
计算二进制中1的个数
运行结果:
$ ./a.out 
64 3 3 40
0x64 = 0110 0100 (共3个1)
0x40 = 0100 0000
*************************************************/

/* 计算一个数(32位无符号)的二进制中1的个数
 * 以x = 999测试,34条指令,占4个字节栈空间
 */
unsigned int binary_count(unsigned int x)
{
        unsigned int count = 0;
        while (x)
        {
                count++;
                //x = x&(x-1); /* 与 */
                x &= x-1;         /* 与 */
                #ifdef DEBUG
                printf("%x ", x);  /* debug */
                #endif
        }
        return count;
}

/* 另一个版本
 * 以x = 999测试,30条指令,不占栈空间
 * 最后一语句x & 0x0000003f, 因为32位1的个数最多只能是32位。
 */
unsigned int ones32(register unsigned int x)
{
         /* 32-bit recursive reduction using SWAR...
           but first step is mapping 2-bit values
           into sum of 2 1-bit values in sneaky way
        */
        x -= ((x >> 1) & 0x55555555);
        x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
        x = (((x >> 4) + x) & 0x0f0f0f0f);
        x += (x >> 8);
        x += (x >> 16);
        return(x & 0x0000003f);
}

/* 求一个数中的MSB */
unsigned int msb32(register unsigned int x)
{
        x |= (x >> 1);
        x |= (x >> 2);
        x |= (x >> 4);
        x |= (x >> 8);
        x |= (x >> 16);
        return(x & ~(x >> 1));
}

/* ?? */
unsigned int tzc(register int x)
{
        return(ones32((x & -x) - 1));
}

int main(void)
{
        unsigned int x = 100;
        unsigned int y = ones32(x);
        unsigned int tmp = binary_count(x);
        unsigned int tmp1 = msb32(x);
        printf("%x %x %x %x/n", x, y, tmp, tmp1);

        return 0;
}

/*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* 二进制中1的个数 结束
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
#endif