C编程和error_code变量效率

时间:2009-12-02 13:31:01

标签: c cpu-architecture micro-optimization machine-instruction low-level-code

我读过的大多数代码都使用int进行标准错误处理(从函数返回值等)。但我想知道使用uint_8编译器是否有任何好处 - 阅读:大多数架构上的大多数C编译器 - 使用立即地址模式生成指令 - 即嵌入1-字节整数进入指令?我正在考虑的关键指令是函数之后的比较,使用uint_8作为其返回类型,返回。

我可能会错误地思考问题,因为引入1字节类型只会导致对齐问题 - 可能有一个完全理智的原因,为什么编译喜欢用4字节打包东西,这可能是每个人只是使​​用整数的原因 - 因为这是与堆栈相关的问题而不是堆,所以没有真正的开销。

做正确的事是我正在考虑的事情。但是让我们说为了论证而说这是一款用于智能手表的流行廉价微处理器,它配置了1k内存,但在其指令集中有不同的寻址模式:D

稍微专门讨论(x86)的另一个问题是:是文字:

uint_32 x=func(); x==1;

uint_8 x=func(); x==1;

同一类型?或者编译器会在第二种情况下生成一个8字节的文字。如果是这样,它可以使用它来生成比较指令,该指令将文字作为立即值并将返回的int作为寄存器引用。 See CMP instruction types.

Another Refference for the x86 Instruction Set.

4 个答案:

答案 0 :(得分:4)

以下是一个特定编译器将对以下代码执行的操作:

extern int foo(void) ;
void bar(void)
{
        if(foo() == 31) { //error code 31
                do_something();
        } else {
                do_somehing_else();
        }
}

   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 08                sub    $0x8,%esp
   6:   e8 fc ff ff ff          call   7 <bar+0x7>
   b:   83 f8 1f                cmp    $0x1f,%eax
   e:   74 08                   je     18 <bar+0x18>
  10:   c9                      leave
  11:   e9 fc ff ff ff          jmp    12 <bar+0x12>
  16:   89 f6                   mov    %esi,%esi
  18:   c9                      leave
  19:   e9 fc ff ff ff          jmp    1a <bar+0x1a>

cmp的3字节指令。如果foo()返回一个char,我们得到  b:3c 1f cmp $ 0x1f,%al

如果你正在寻找效率。不要假设比较%a1中的内容比比较%eax

更快

答案 1 :(得分:3)

特定架构上的不同整数类型之间可能存在非常小的速度差异。但是你不能依赖它,如果你转移到不同的硬件,它可能会改变,如果你升级到更新的硬件,它甚至可能运行得更慢。

如果你在给出的例子中讨论x86,你会做出一个错误的假设:即时需要是uint8_t类型。

实际上,嵌入到指令中的8位immediates属于int8_t类型,可以使用C表示法中的字节,单词,双字和qwords:charshort,{ {1}}和int

因此,在这种架构上,根本没有任何好处,无论是代码大小还是执行速度。

答案 2 :(得分:3)

您应该使用int或unsigned int类型进行计算。仅对化合物(结构/数组)使用较小的类型。原因是int通常被定义为处理器的“最自然”整数类型,所有其他派生类型可能需要处理才能正常工作。我们在我们的项目中使用gcc在Solaris上为SPARC编译了访问8位和16位变量的情况,为代码添加了一条指令。从内存加载较小的类型时,必须确保正确设置寄存器的上半部分(符号类型的符号扩展名为0或无符号的符号)。这使得代码更长,并增加了寄存器的压力,这使其他优化变得更糟。

我有一个具体的例子:

我将结构的两个变量声明为uint8_t并在Sparc Asm中获得该代码:

    if(p->BQ > p->AQ)

已翻译成

ldub    [%l1+165], %o5  ! <variable>.BQ,
ldub    [%l1+166], %g5  ! <variable>.AQ,
and     %o5, 0xff, %g4  ! <variable>.BQ, <variable>.BQ
and     %g5, 0xff, %l0  ! <variable>.AQ, <variable>.AQ
cmp     %g4, %l0    ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL586  !

这就是我将两个变量声明为uint_t

时的结果
lduw    [%l1+168], %g1  ! <variable>.BQ,
lduw    [%l1+172], %g4  ! <variable>.AQ,
cmp     %g1, %g4    ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL587  !

两个算术运算较少,2个寄存器多用于其他东西

答案 3 :(得分:1)

处理器通常喜欢使用它们的自然寄存器大小,其中C是'int'。

虽然有例外,但你对一个不存在的问题考虑得太多了。