上个月积累的代码如下,由于在同一文件中测试多个代码段,因此只好用#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。本文所有代码片段可任意使用而不用告诉作者,当然,作者修改了也不必要告知阁下,而且,由于代码的错误而造成的损失亦与作者无关,不过一起讨论、学习还是可以的。
/*************************************************
没有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