编译器对你的c++代码做了什么?

在实际项目中,偶尔会出现运行情况与预想情况不一致的现象,这可能是忽略了编译器对你代码的改动与优化(当然,你写错代码的可能性更高)。不管怎么样,我们还是来看看编译器到底偷偷给你整了什么好活吧。

1. 短函数自动转为inline内联函数

当函数较短且不存在for/while等循环条件时,编译器会默认将其转换为内联函数展开,提高对应的执行效率,减少调用函数的堆栈消耗。

2. sizeof操作符

直接在编译阶段根据参数类型推断大小,如果是函数则不会调用(如sizeof(func(a));),根据函数返回值类型推断结果就好了。即在目标程序中,这里已经被替换为一个常数了。这个算是常见笔试题的考点了,如果对sizeof有正确认知的话一般不会出错。

3. 右值优化

c++11编译会优化函数返回值,采用右值传参直接转移内存数据。该优化可以通过编译参数-fno-elide-constructors关闭,默认开启。此项开启后,就不会按照原先预想的调用拷贝构造函数等操作(虽然实际并无害处,效率更高了),而是转让内存所有权。

4. 无效代码优化

未被使用的变量或者函数不会编译进目标程序中。如函数仅声明未实现,未被调用的情况下是可以编译通过的。此处的“未被调用”一般指编译器通过main函数或者全局变量/静态变量等进行推导,判断其是否存在可能被调用的代码执行路径。

但在实际项目中,可能会存在一些原因导致函数被误判为“未被调用”,其本身又未被实现,这就导致程序编译能通过,但在实际运行过程中找不到函数实现最终崩溃。

5. ++操作

这里涉及一个比较常见的笔试题,"a=++a+a++"。首先声明一点,在C语言中这种单条语句多次修改同一变量值的操作视为未定义行为(undefined behavior),结果往往由编译器决定,因此不推荐实际项目中使用这种写法,可读性也不高。

不过在一般情况下,++a和a++可以等同于以下函数:

// ++a
int incrby_bf(int &a) {
	a = a + 1;
	return a;
}
// a++
int incrby_af(int &a) {
	a = a + 1;
	return a - 1;
}

即a=++a+a++;可以替换为a=incrby_bf(a)+incrby_af(a);。此处也有一个需要注意的点:incrby_bf和incrby_af函数的执行顺序由编译器决定,并不是固定从左到右计算的。因此如果两个函数存在前后执行的依赖关系,建议把语句拆成两部分执行。

更详细的内容可以查看这位大佬的博客:用异或来交换两个变量是错误的,其中还采用了实际的测试数据进行考究。

6. 构造函数推断

在c++中,编译中会根据变量定义时赋值的参数自动判断对应的构造函数,而不是先走默认构造函数再进行赋值,增加了额外的赋值操作。在以下代码中,变量tmp(显式调用)与tmp2(隐式调用)的定义操作是等同的。

class TestClass {
public:
	TestClass() {
		puts("default constructor");
	}
	TestClass(const char *str) {
		puts("chars constructor");
	}
};

int main() {
	TestClass tmp("hello");
	TestClass tmp2 = "hello";
	return 0;
}

但如果参数的推断类型存在中间转换,目前一些编译器暂时无法识别,如以下代码:

class TestClass {
public:
	TestClass() {
		puts("default constructor");
	}
	TestClass(const std::string &str) {
		puts("string constructor");
	}
};

int main() {
	TestClass tmp("hello");
	TestClass tmp2 = "hello";
	return 0;
}

显式调用的tmp可以直接调用string做参数的构造函数,而隐式调用的tmp2则会出现编译报错(无法在TestClass类中找到const char*类型的构造函数)。从该处可以得知,编译器的构造函数推断仅限于完全一致的参数类型,存在中间转换的参数是不支持的。

 

 

 

 

 

 

 

 

 

 

 

 

c++编译器对代码做的改动其实非常多,毕竟编译器开发人员也不是吃干饭的,总会根据实际情况进行优化和调整。在本篇博客中只是提到了少数的几点编译器处理操作,之后还会继续更新补充呦。

奇怪的知识又增加了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值