标签(空格分隔):《C++高效编程》
本博客是看《C++高效编程》的笔记,还在更新中。。。
书张这样:
第一部分扯蛋,没怎么看,直接看第二部分。的确是好书,值得一看。
gcc -s hello.c
gcc -c hello.c
gcc -E hello.c
gcc -E hello.c >> output.txt 输出结果放入一个文件中【>> 流操作】
c++内嵌汇编实例
#include
#include
using namespace std;
const int mmax = 100;
void change_xyz(int x, int y)
{
int z = 3;
printf("x, y, z %d %d %d\n", x, y, z);
asm("movl $4,8(%ebp)");
asm("movl $5,12(%ebp)");
asm("movl $6,12(%esp)");
printf("x, y, z %d %d %d\n", x, y, z);
}
int main()
{
int x = 1, y = 2;
change_xyz(x, y);
return 0;
}
生成可执行代码
gprof test > test.out
据说能显示程序运行时间。
gcc -Wall hello.c -o hello
简直就是某些VS用户的福利呀,clion自带检查所以不需要,哈哈
优化1:循环要用到某些量放外面
int isprime(int n)
{
for(int i = 2; i < sqrt(n); i++)
{
if(n % i == 0)
return 0;
}
return 1;
}
换为:
int isprime(int n)
{
int nn = sqrt(n);
for(int i = 2; i < nn; i++)
{
if(n % i == 0)
return 0;
}
return 1;
}
int f1(int a)
{
return a*a-2*a-10;
}
void f2(int n)
{
for(int i = 0; i < n; i++)
{
if(f(i)>0)
printf("-.-");
}
}
换成:
int f1(int a)
{
return a*a-2*a-10;
}
void f2(int n)
{
int d = f(0);
for(int i = 1; i < n; i++)
{
if(d>0)
printf("~(-V-)~\n");
d = d + 2*i-1;//少算一个乘法,嘿嘿
}
}
优化2:少用成员变量和成员函数
书上提到:存取成员变量是局部变量的两倍,这是因为要用this指针来获得成员变量的基地址。
void f(int n)
{
for(int i = 0; i < XX.GetSize(); i++)
{
sum += XX.num;
}
}
改为:
void f(int n)
{
int XXsize = XX.GetSize();
int XXnum = XX.num;
for(int i = 0; i < XXsize; i++)
{
sum += XXnum;
}
}
你有没有想过一个结构会因为写法不同而产生不同的大小?
我们看一段简单的程序:
#include
#include
using namespace std;
struct A
{
char a;
long b;
char c;
long d;
};
struct B
{
char a;
char c;
long b;
long d;
};
#pragma pack(push, 1)
struct C
{
char a;
long b;
char c;
long d;
};
#pragma pack(pop)
int main()
{
printf("%d\n", sizeof(A));
printf("%d\n", sizeof(B));
printf("%d\n", sizeof(C));
return 0;
}
结果是32, 24, 18
为什么呢?
我们看一下储存结构:(long 类型字节顺序随系统不同而不同)
A地址 | 内容 |
---|---|
00 | 字符a |
01 | 未用 |
02 | 未用 |
03 | 未用 |
04 | long b, byte 0 |
05 | long b, byte 1 |
06 | long b, byte 2 |
07 | long b, byte 3 |
结构B更为紧凑
A地址 | 内容 |
---|---|
00 | 字符a |
01 | 字符c |
02 | 未用 |
03 | 未用 |
04 | long b, byte 0 |
05 | long b, byte 1 |
06 | long b, byte 2 |
07 | long b, byte 3 |
A,B的区别告诉我们:原来我们储存struct时会以最大的数据类型作为基准来放数据。这叫类型对齐
结构C没有空隙
A地址 | 内容 |
---|---|
00 | 字符a |
01 | long b, byte 0 |
02 | long b, byte 1 |
03 | long b, byte 2 |
04 | long b, byte 3 |
05 | 字符c |
06 | long d, byte 0 |
07 | long d, byte 1 |
编译指令#pragma pack可以让编译器暂时调整对齐
先用push命令把当前的对齐方式放入编译器栈堆中,最后pop回到初始对齐方式。
1是两个变量的间距。例:当把char换为short时,我们的命令为:
#pragma pack(push, 2)
struct C
{
short a;
long b;
short c;
long d;
};
#pragma pack(pop)
比特域是一种极端的变量对齐方式。它直接指定变量的比特大小。
比特域举例
#include
#include
using namespace std;
struct A
{
int n1:11;//long1
int n2:11;
int n3:10;
int n4:11;//long2
int n5:11;
int n6:10;
};
int main()
{
printf("%d", sizeof(A));//8
return 0;
}
编译器会把整个结构压缩在两个long类型中,因此结构体内变量的顺序是十分重要的。
错误的举例
#include
#include
using namespace std;
struct A
{
int n1:11;//long1
int n2:11;
int n3:11;//long2
int n4:11;
int n5:10;
int n6:10;//long3
};
int main()
{
printf("%d", sizeof(A));//12
return 0;
}
比特域节省空间,那它的效率如何呢?书上举了一个例子,同一个程序用struct Bitfield{unsigned num: 11;};与struct Structure{short num;};两种不同的结构,比特域的汇编长度是short的好几倍(书上例子中是三倍)
另外书上补充说明了比特域的写法。
错误举例
struct F
{
unsigned a, b : 4;//创建了一个32位的比特域和4位的比特域。
}
可以在一个结构中包含比特域和基本类型,但不提倡,因为只要结构中出现比特域,所有变量都会以long为基准。
struct C
{
char a;//long
unsigned b :4;
}
就像上面这个结构体,a,b存在一个long中。
最后,比特域无法使用地址,无法对比特域初始化引用。
联合可以使几个变量共享一块存储空间,联合的大小就是它所包含的最大元素的大小。
同时联合的优点也是它的缺点,当我们经常使用联合中大小较小的变量时,就不考虑使用联合了。