【问题标题】:Does optimization change the behavior of casts?优化会改变强制转换的行为吗?
【发布时间】:2015-05-10 19:02:30
【问题描述】:

我正在使用小型 UART 设备,并且经常需要切换其运行的波特率。
基本上整个设置归结为

#define FOSC 2000000
#define BAUD 9600

uint8_t rate = (uint8_t) ((FOSC / (16.0 * BAUD)) - 1 + 0.5);

(其中 +0.5 用于对结果进行四舍五入。)

我目前正在使用 gcc 4.8.1 进行编译,-O1
编译器是否优化了整个演员表,还是我留下了演员表后跟一个常量?这会因不同的-O# 值而有所不同(-O0 除外)? -Os (我最终可能必须编译)呢?

如果重要的话,我正在为Atmel AT90USB647(或datasheet [pdf])开发。

【问题讨论】:

  • 嗯?预处理只是字符串替换。它不处理语义级别的任何事情。
  • 也就是说:你可以问uint8_t rate = (uint8_t) (2000000 / (16.0 * 9600)) - 1 + 0.5,把预处理器排除在外。
  • 简短的回答,不过——这将成为 gcc4 上的编译时常量,甚至可能使用 -O0,但肯定会使用其他任何东西。
  • @user1320881,我猜 OP 认为强制转换操作有运行时成本?
  • -S编译并查看汇编文件.s

标签: c gcc gcc4


【解决方案1】:

极有可能在启用优化的情况下编译时,任何理智的编译器都会将整个表达式(包括强制转换)转换为常量。

但是,可以肯定的是,您需要查看编译器的汇编输出。

但是特别是 GCC 4.8.1 呢?

代码

#include <stdint.h>
#include <stdio.h>

#define FOSC 2000000
#define BAUD 9600

int main() {
    uint8_t rate = (uint8_t) (FOSC / (16.0 * BAUD)) - 1 + 0.5;
    printf("%u", rate);
}

生成的程序集部分带有gcc -O1 red.c

main:
.LFB11:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $12, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf

我们可以清楚地看到,gcc 已经为rate 预先计算了12 的值。

【讨论】:

  • 问题被标记为gcc4,所以我们可以假设编译器。
  • 我认为平台和硬件也很重要。 OP 很可能希望在嵌入式设备上运行此代码。
  • @Barracuda:生成的程序集可能不同,但持续传播优化过程适用于任何架构。
  • @BillLynch 我以前也这么认为,但我个人看到gcc 将未初始化的整数值优化到它们的最大值或0 在相同的代码中,它应该在ARM 处理器上运行。
  • @Barracuda:值等于的常数可能因intlongdouble 的大小而异。但这并不意味着编译器不会将其推送到常量。
【解决方案2】:

Atmel AVR 提供newlib C 库,它是一个简单的 ANSI C 库、数学库和板级支持包集合。您可以参考 ANSI C 规范来找出答案。特别是转换部分。

【讨论】:

    【解决方案3】:

    我会确保将速率写入 volatile 变量或指针。也许速率值计算得很好,但是当它被写入外围目的地时,它缺少 volatile 标记并且优化器不执行写入操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 2015-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多