C编程和error_code变量效率

发布于 2024-08-13 04:32:15 字数 829 浏览 8 评论 0原文

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

我可能错误地思考了事情,因为引入 1 字节类型只会导致对齐问题 - 可能有一个完全理智的原因为什么编译喜欢将东西打包在 4 字节中,这可能是每个人都只使用 int 的原因 - 并且由于这是与堆栈相关的问题而不是与堆相关的问题,因此没有真正的开销。

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

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

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

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

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

x86 指令集的另一个参考。

Most code I have ever read uses a int for standard error handling (return values from functions and such). But I am wondering if there is any benefit to be had from using a uint_8 will a compiler -- read: most C compilers on most architectures -- produce instructions using the immediate address mode -- i.e., embed the 1-byte integer into the instruction ? The key instruction I'm thinking about is the compare after a function, using uint_8 as its return type, returns.

I could be thinking about things incorrectly, as introducing a 1 byte type just causes alignment issues -- there is probably a perfectly sane reason why compiles like to pack things in 4-bytes and this is possibly the reason everyone just uses ints -- and since this is stack related issue rather than the heap there is no real overhead.

Doing the right thing is what I'm thinking about. But lets say say for the sake of argument this is a popular cheap microprocessor for a intelligent watch and that it is configured with 1k of memory but does have different addressing modes in its instruction set :D

Another question to slightly specialize the discussion (x86) would be: is the literal in:

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

and

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

the same type ? or will the compiler generate a 8-byte literal in the second case. If so it may use it to generate a compare instruction which has the literal as an immediate value and the returned int as a register reference. See CMP instruction types..

Another Refference for the x86 Instruction Set.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

埖埖迣鎅 2024-08-20 04:32:15

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

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 比较更快

Here's what one particular compiler will do for the following code:

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>

a 3 byte instruction for the cmp. if foo() returns a char , we get
b: 3c 1f cmp $0x1f,%al

If you're looking for efficiency though. Don't assume comparing stuff in %a1 is faster than comparing with %eax

云仙小弟 2024-08-20 04:32:15

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

如果您在给出的示例中谈论 x86,您就会做出错误的假设:立即数需要为 uint8_t 类型。

实际上,嵌入到指令中的 8 位立即数是 int8_t 类型,可以与字节、字、双字和 qword 一起使用,采用 C 表示法:charshortintlong long

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

There may be very small speed differences between the different integral types on a particular architecture. But you can't rely on it, it may change if you move to different hardware, and it may even run slower if you upgrade to newer hardware.

And if you talk about x86 in the example you are giving, you make a false assumption: An immediate needs to be of type uint8_t.

Actually 8-bit immediates embedded into the instruction are of type int8_t and can be used with bytes, words, dwords and qwords, in C notation: char, short, int and long long.

So on this architecture there would be no benefit at all, neither code size nor execution speed.

甚是思念 2024-08-20 04:32:15

您应该使用 int 或 unsigned int 类型进行计算。仅对复合(结构/数组)使用较小的类型。原因是 int 通常被定义为处理器的“最自然”整数类型,所有其他派生类型可能需要处理才能正确工作。我们在 Solaris 上使用 gcc 为 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 个寄存器其他东西

You should use int or unsigned int types for your calculations. Using smaller types only for compounds (structs/arrays). The reason for that is that int is normally defined to be the "most natural" integral type for the processor, all other derived type may necessitate processing to work correctly. We had in our project compiled with gcc on Solaris for SPARC the case that accesses to 8 and 16 bit variable added an instruction to the code. When loading a smaller type from memory it had to make sure the upper part of the register was properly set (sign extension for signed type or 0 for unsigned). This made the code longer and increased pressure on the registers, which deteriorated the other optimisations.

I've got a concrete example:

I declared two variable of a struct as uint8_t and got that code in Sparc Asm:

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

was translated in

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  !

And here what I got when I declared the two variables as 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  !

Two arithmetic operations less and 2 registers more for other stuff

奈何桥上唱咆哮 2024-08-20 04:32:15

处理器通常喜欢使用其自然寄存器大小,在 C 中为“int”。

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

Processors typically likes to work with their natural register sizes, which in C is 'int'.

Although there are exceptions, you're thinking too much on a problem that does not exist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文