gcc是否会优化对相同变量的重复函数调用,并为每次调用提供相同的输出?
Will gcc optimize away repeated function calls upon the same variable with same output for each call?
对于一个应用程序,我的情况是相同的信息以多种形式存在:Base64字符串,十六进制字符串和char[]
。
现在,为了提高效率,不要费力地声明&对每个函数初始化一次变量,我只在上述形式之间明显的转换点上应用它。原因是,在某些点上,变量不需要转换为另一种形式,以进行条件比较等操作。
从我所读到的,看起来好像编译器是令人难以置信的高效,而且越来越高效;然而,当我试图阅读更深入的分析和描述时,我经常超过我经验的极限,我的大脑堆栈溢出。
如果一个函数被反复调用到一个变量,把它变成另一种形式,比如从Base64字符串到十六进制字符串,每次都产生相同的结果,编译器会优化这些调用,使为整个作用域声明的变量是不必要的吗?
在我的情况下,我使用-Ofast
,直到有更好的东西。
编译器可以优化掉的东西实际上取决于代码是如何编写的;然而,依赖编译器过于聪明通常是不明智的。编译器在优化寄存器分配和各种低级别的东西方面做得很好,但是如果你知道你的程序中有一些不变量可以让代码更有效地编写,不要认为编译器理解整个程序。
对于您提到的这个特定示例,如果您将数据包装在实现各种格式转换操作符的类中,并缓存转换结果,这将是比依赖编译器不重做相同计算更好的方法。但是,如果将这些转换操作符标记为"const",则有可能(假设没有执行交错的非const操作)编译器将重用先前调用"const"方法的结果。但是,我建议在缓存结果的基础上再执行这个操作,而不是依赖于这个优化。
而且,当涉及到这些优化时,唯一确定的方法是使用特定的编译器实际编译代码并检查汇编输出以确定它是否应用了该优化。
我希望gcc
不会执行这种优化。如果是这样,就必须满足几个要求,比如被调用的函数同时被编译,以提供跨调用优化寄存器的可能性。
这样的优化令人印象深刻,但并不完全有用。程序员可以很容易地编写对函数的调用并保存返回值。
CDC Cyber (c. 1975) FORTRAN编译器有一些有趣的行为。它将优化对IRAND()
的调用。这让许多编写游戏的学生感到惊讶和困惑,就像下面的掷两个骰子的片段:
integer roll
roll = mod (irand(0), 6) + mod (irand(0), 6) + 2
这只产生偶数,因为它认为它好像写的是
roll = 2 * mod (irand(0), 6) + 2
它被报告为1978年左右的一个错误,通过不优化涉及irand()
或rand()
的表达式来修复。这很容易通过使其难以优化来解决:
integer roll, die1, die2
die1 = mod (irand(0), 6) + 1
die2 = mod (irand(0), 6) + 1
roll = die1 + die2
只要优化不是太高,它就会像预期的那样工作。第一个例子是总是优化:它不能被关闭。
这里有一段代码来说明这个概念:
class TriString
{
public:
enum Format { Binary, Hex, Base64 };
TriString(const std::string& s) : s_(s) { }
// mutators - must modify b_ and h_ accordingly or clear them
TriString& operator=(const std::string& rhs)
{ s_ = rhs; b_.clear(); h_.clear(); }
TriString& erase(size_type index = 0, size_type count = npos)
{
s_.erase(index, npos);
h_.clear(); // will need regeneration...
b_.erase(index * 2, count == npos ? npos : count * 2);
}
char& operator[](size_type n)
{
h_.clear();
b_.clear();
return s_[n];
}
// ...add more as needed...
// accessors
const std::string& get(Format) const
{
if (Format == Binary || s_.empty())
return s_;
if (Format == Hex)
{
if (h_.empty()) h_ = to_hex(s_);
return h_;
}
// Format == Base64
if (b_.empty()) b_ = to_base64(s_);
return b_;
}
const char& operator[](size_type n) const { return s_[n]; }
// ...add more as needed...
private:
std::string s_; // normal string
// "cached" conversions - invariant: valid if not empty(), or s_.empty() too
// (mutable so get(Format) const can modify despite being const)
mutable std::string b_; // base64 encoded
mutable std::string h_; // hex encoded
};
使用通常的std::string
接口执行此操作并不安全,因为像下面这样的客户端代码将不起作用:
TriState s("hello!");
char& c = s[2];
const std::string& h = s.get(TriState::Hex); // triggers caching of hex conversion
c = 'x'; // oops - modifies s_ without clearing/updating h_
const std::string& h2 = s.get(TriState::Hex); // oops - gets old cached h_ despite changed s_
您必须做出一些选择,要么限制接口以避免授予持续更改字符串的能力(如非const operator[]
,迭代器等),返回代理对象(而不是例如字符引用),可以在写入时清除缓存的转换,或者记录一些客户端使用的限制并希望得到最好的....
- 当使用通配符和null指针调用函数时,对输出的说明
- 有没有办法简单地从 GPU 调用多个 cpp 输出文件?
- 使用静态变量的递归调用的不同输出
- cmake add_custom_command + Xcode:多输出 = 多命令调用
- 调用 cout 时如何在结构中输出常量文本?
- 我的 cout 上有一个奇怪的输出,它把答案放在第一位,然后在我调用它的地方放一个奇怪的输出.我该怎么办?
- 函数调用导致没有输出
- 使用 Node.js N-API 调用 C 函数时,不会显示预期的输出
- 如何调用继承的重载运算符<<并在派生类的输出中添加更多文本?
- 我的动态链接队列在同一输出流中调用时不正确地输出三个返回函数
- 当我从头文件和实现文件调用我的函数到我的主文件时,我没有得到任何输出
- 空指针(为缺少的输出数组调用的 create() 在 create,文件 /home/m/OpenCV/modules/
- 为什么在杂注 omp 关键之后多次调用 printf 会产生乱码输出?
- std::cout 如果从自定义分配器 (Visual Studio 2019) 调用,则不会输出
- 将 Linux system() 调用命令的输出重定向到仅可变的
- QThread 不提供来自调用 shellscript 的输出
- 显示 matlab 程序的输出,调用另一个 C++ 程序
- 输出 = 0 尝试计算标头中的函数并在主程序中调用它们时
- 基于对函数的参数调用流输出运算符的能力重载函数
- 使用读取系统调用C++输出文本