关于Padding,请看下面的代码:
#pragma pack(1)
struct A
{
char c;
int i;
};
#pragma pack()
struct A2
{
char c;
int i;
};
我们可以assert:
assert(sizeof(A) == 5);
assert(sizeof(A2) == 8); // 假设32位编译环境
这里的padding大小我们基本都可以预测。
由于c++模板的代码生成规则,下面的代码可能不会注意到
template<typename T>
struct BT
{
int a;
};
#pragma pack(1)
struct B
{
char c;
BT b;
};
#pragma pack()
struct B2
{
char c;
BT b;
};
这时sizeof(B2)以及B2::b的偏移地址是多少?
struct BT第一次被实例化是在struct B内,且此时的pack为1.于是该类的alienment也被当作1来处理
到后面的B2内,虽然pack已经恢复(为4)但b的alienment值仍然为1,于是sizeof(B2)==5而B2::b的偏移为1而不是4
注意:在vc上,这个sizeof(B2)==8,B2::b的偏移为4,仍然是我们所期望的。
首先感谢xq; lj定位问题!
问题出在我签入的来自卡马克的求平方根函数代码。

Code
double InvSqrt(double number)
{
__int64 i;
double x2, y;
const double threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = *(__int64 *)&y;
i = 0x5fe6ec85e7de30da - (i >> 1);
y = *( double *)&i;
y = y * (threehalfs - (x2 * y * y)); //1st iteration
y = y * (threehalfs - (x2 * y * y)); //2nd iteration, this can be removed
return y;
}
红色部分代码在gcc开启-fstrict-aliasing选项后将得到错误的代码。由于使用了type-punned pointer将打破strict-aliasing规则。
由于-fstrict-aliasing选项在-O2, -O3, -Os等优化模式下都将开启(目前dev不带优化,main带-O3所以该问题只在main上出现)所以建议对linux编译中产生
warning: dereferencing type-punned pointer will break strict-aliasing rule
警告的情况作为编译失败。以便防止出现类似问题。
上述代码应当使用联合体重写为:

Code
double InvSqrt(double number)
{
double x2, y;
const double threehalfs = 1.5F;
union
{
double d;
__int64 i;
}d;
x2 = number * 0.5F;
y = number;
d.d = y;
d.i = 0x5fe6ec85e7de30da - (d.i >> 1);
y = d.d;
y = y * (threehalfs - (x2 * y * y)); //1st iteration
y = y * (threehalfs - (x2 * y * y)); //2nd iteration, this can be removed
return y;
}
这样就不会打破该规则。
什么是Strict Aliasing?请看:http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html?
In C99, it is illegal to create an alias of a different type than the original.
在我们现在的代码中可以按正则表达式\([^()]+\*:b*\):b*&找到约180个匹配行,涉及60个文件。
这其中应该有一些是不符合这个strict-aliasing要求的。
处理方法
1是临时关闭strict-aliasing选项:在使用-O2, -O3, -Os编译的情况下使用-fno-strict-aliasing关闭strict-aliasing
2是要修改这类不满足该限制的代码,在完全修改完毕之后再打开。
要注意到,strict-aliasing选项提示编译器代码满足这个限制,所以可以提供编译器进行额外的代码优化的机会。
1:代码不一致(编译)
2:内存不够用了(看看那个进程占了这么多)
3:符号文件被其他进程锁住了(一般是多个vs造成的,把VS关掉,检查是否有devenv.exe/mspdbsrv.exe死进程)
by 教练
使用VA后,因为要在一台机器上调试客户端和服务器,之前一直卡到不行.
后面找到方法,关闭vs2005自带的提示功能,这样速度会快不少,
具体方法很简单,把
..\Miscrosoft Visual Studio 8\VC\Vcpackages\feacp.dll 删除或者改名即可
by 万hb
仿佛.ilk文件超过了200兆就会造成增量链接失败,链接时提示如下:
LINK: warning LNK4076:无效的增量状态文件”xxx.ilk”;正在非增量链接
尚不知道如何避免,临时处理方法是添加一个预生成事件,当增量链接文件大于200兆就先删除它再继续生成
具体操作方法如下:
选中出现该情况的项目,编辑它的属性
配置属性->生成事件->预生成事件->命令行
for /R $(OutDir) %%i in ($(TargetName).ilk) do if /i %%~zi GTR 200000000 (del %%~fi)
说明中可以填写一个提示,比如: 当增量链接文件大于200兆就先删除它再继续生成
/LTCG, 链接时代码生成, 由于在链接时生成代码,可以全局地对所有obj进行优化. 一般用于release版的生成. 该选项与增量链接是冲突的.
开启了链接时代码生成,即便在增量链接开启的情况下,仍然要进行完整链接.
为了让Debug版本生成速度不变慢,请保持Debug版本不使用链接时代码生成选项.并且也不要依赖带有/LTCG选项生成的库