相关疑难解决方法(0)

将字符串作为指针或文字传递时,strcmp()返回值不一致

strcmp当我注意到这一点时,我正在玩,这里是代码:

#include <string.h>
#include <stdio.h>

int main(){

    //passing strings directly
    printf("%d\n", strcmp("ahmad", "fatema"));

    //passing strings as pointers 
    char *a= "ahmad";
    char *b= "fatema";
    printf("%d\n",strcmp(a,b));

    return 0;

}
Run Code Online (Sandbox Code Playgroud)

输出是:

-1
-5
Run Code Online (Sandbox Code Playgroud)

不应该strcmp一样吗?为什么,我给我传递一个字符串作为不同的值"ahmad"或作为char* a = "ahmad".将值传递给函数时,它们是否在其堆栈中分配?

c c++ linux strcmp

32
推荐指数
2
解决办法
1852
查看次数

哪些 GCC 优化标志对二进制大小影响最大?

我正在使用 GCC 为 ARM 开发 C++。我遇到了一个问题,我没有启用优化,我无法为我的代码创建二进制文件(ELF),因为它不适合可用空间。但是,如果我只是启用调试优化(-Og)(据我所知这是可用的最低优化),代码就很容易适应。

在这两种情况下,都会启用-ffunction-sections-fdata-sections-fno-exceptions-Wl,--gc-sections 。

  • 闪存大小:512 kB
  • 没有优化:.text 溢出约 200 kB
  • 使用-Og优化:.text 约为 290 kB

即使进行了最小的优化,二进制大小也存在巨大差异。

我查看了3.11 控制优化的选项,详细了解使用 -Og 标志执行哪些优化,看看这是否会给我任何见解。

哪些优化标志对二进制大小影响最大?我应该寻找什么来解释这种巨大的差异吗?

c++ gcc arm code-size compiler-optimization

29
推荐指数
2
解决办法
9484
查看次数

为什么循环总是被编译成"do ... while"样式(尾部跳转)?

当试图理解汇编(启用编译器优化)时,我看到这种行为:

这样一个非常基本的循环

outside_loop;
while (condition) {
     statements;
}
Run Code Online (Sandbox Code Playgroud)

经常被编译成(伪代码)

    ; outside_loop
    jmp loop_condition    ; unconditional
loop_start:
    loop_statements
loop_condition:
    condition_check
    jmp_if_true loop_start
    ; outside_loop
Run Code Online (Sandbox Code Playgroud)

但是,如果未打开优化,则会编译为通常可理解的代码:

loop_condition:
    condition_check
    jmp_if_false loop_end
    loop_statements
    jmp loop_condition  ; unconditional
loop_end:
Run Code Online (Sandbox Code Playgroud)

根据我的理解,编译后的代码更像是这样的:

goto condition;
do {
    statements;
    condition:
}
while (condition_check);
Run Code Online (Sandbox Code Playgroud)

我看不到巨大的性能提升或代码可读性提升,为什么经常出现这种情况呢?是否有此循环样式的名称,例如"尾随条件检查"?

optimization performance assembly loops micro-optimization

26
推荐指数
1
解决办法
1675
查看次数

当我在禁用优化的情况下进行编译时,为什么clang不使用内存目标x86指令?它们有效吗?

我编写了这个简单的汇编代码,运行它并使用GDB查看内存位置:

    .text

.global _main

_main:
    pushq   %rbp
    movl    $5, -4(%rbp)
    addl    $6, -4(%rbp)
    popq    %rbp
    ret
Run Code Online (Sandbox Code Playgroud)

它直接在内存中添加5到6个,根据GDB它可以工作.所以这是直接在内存中执行数学运算而不是CPU寄存器.

现在在C中编写相同的东西并将其编译为汇编,结果如下:

...  # clang output
    xorl    %eax, %eax
    movl    $0, -4(%rbp)
    movl    $5, -8(%rbp)
    movl    -8(%rbp), %ecx   # load a
    addl    $6, %ecx         # a += 6
    movl    %ecx, -8(%rbp)   # store a
....
Run Code Online (Sandbox Code Playgroud)

在将它们添加到一起之前,它会将它们移动到寄存器中.

那么为什么我们不直接在内存中添加?

它慢了吗?如果是这样,为什么直接在内存中添加甚至允许,为什么汇编程序在开始时没有抱怨我的汇编代码?

编辑:这是第二个程序集块的C代码,我在编译时禁用了优化.

#include <iostream>

int main(){
 int a = 5;
 a+=6; 
 return 0;
}
Run Code Online (Sandbox Code Playgroud)

c assembly gcc clang compiler-optimization

19
推荐指数
1
解决办法
1214
查看次数

为什么 for 循环体中的一个基本算术运算执行得比两个算术运算慢?

当我尝试测量算术运算的执行时间时,我遇到了非常奇怪的行为。包含for循环体中具有一个算术运算的循环的代码块总是比相同的代码块执行得慢,但在for循环体中具有两个算术运算。这是我最终测试的代码:

#include <iostream>
#include <chrono>

#define NUM_ITERATIONS 100000000

int main()
{
    // Block 1: one operation in loop body
    {
        int64_t x = 0, y = 0;
        auto start = std::chrono::high_resolution_clock::now();

        for (long i = 0; i < NUM_ITERATIONS; i++) {x+=31;}

        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << diff.count() << " seconds. x,y = " << x << "," << y << std::endl;
    }

    // Block 2: two operations in loop …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly cpu-architecture google-benchmark

15
推荐指数
3
解决办法
863
查看次数

为什么会发生字节溢出以及它们实现了什么?

什么是字节溢出?

当我从C程序生成的LLVM中间表示转储x86 ASM时,会有大量溢出,通常为4字节大小.我无法弄清楚它们为什么会发生以及它们取得了什么.

他们似乎"切掉"了堆叠的碎片,但是以一种不寻常的方式:

## this fragment comes from a C program right before a malloc() call to a struct.
## there are other spills in different circumstances in this same program, so it
## is not related exclusively to malloc()
...
sub ESP, 84
mov EAX, 60
mov DWORD PTR [ESP + 80], 0
mov DWORD PTR [ESP], 60
mov DWORD PTR [ESP + 60], EAX # 4-byte Spill
call malloc
mov ECX, 60
...
Run Code Online (Sandbox Code Playgroud)

c memory x86 assembly llvm

14
推荐指数
1
解决办法
3042
查看次数

如何在使用内在函数时让GCC使用两个以上的SIMD寄存器?

我正在编写一些代码并尝试使用SIMD内在函数SSE2/3来加速它.我的代码具有这样的性质,我需要将一些数据加载到XMM寄存器中并对其进行多次操作.当我查看生成的汇编程序代码时,GCC似乎不断将数据刷新回内存,以便在XMM0和XMM1中重新加载其他内容.我正在编译x86-64所以我有15个寄存器.为什么GCC只使用两个,我该怎么做才能让它使用更多?有什么方法可以"固定"寄存器中的某些值吗?我在我的变量定义中添加了"register"关键字,但生成的汇编代码是相同的.

x86 assembly gcc sse simd

13
推荐指数
1
解决办法
2327
查看次数

在大数组中有效地找到最低有效设置位?

我有一个巨大的内存块(位向量),在一个内存页中大小为N位,考虑N平均为 5000,即 5k 位来存储一些标志信息。
在某个时间点(超级频繁 - 关键),我需要在整个大位向量中找到第一个位集。现在我每 64 个字都这样做,即在 ) 的帮助下__builtin_ctzll。但是当N增长并且搜索算法无法改进时,可以通过扩展内存访问宽度来扩展此搜索。这是几句话的主要问题

有一条被调用的汇编指令BSF 给出了最高设置位(GCC's __builtin_ctzll())的位置。因此,在 arch 中,我可以在 64 位字中廉价地找到最高位。

但是通过内存宽度进行缩放呢?
例如,有没有办法用 128 / 256 / 512 位寄存器有效地做到这一点?
基本上我对一些 C API 函数来实现这个感兴趣,但也想知道这个方法是基于什么的。

UPD:至于 CPU,我对这种优化感兴趣,以支持以下 CPU 阵容:
英特尔至强 E3-12XX、英特尔至强 E5-22XX/26XX/E56XX、英特尔酷睿 i3-5XX/4XXX/8XXX、英特尔酷睿 i5- 7XX、英特尔赛扬 G18XX/G49XX(英特尔凌动 N2600、英特尔赛扬 N2807、Cortex-A53/72 可选)

PS在最终位扫描之前提到的算法中,我需要将k(平均 20-40)个N位向量与 CPU AND相加(AND 结果只是位扫描的准备阶段)。这也适用于内存宽度缩放(即比每 64 位字 AND 更有效)

另请阅读:查找第一组

c assembly bit-manipulation x86-64 avx

13
推荐指数
2
解决办法
465
查看次数

编译器的“-O0”选项和“-Og”选项有什么区别?

当我想要调试 C 或 C++ 程序时,我被教导如何使用-O0关闭优化,并将-ggdb符号插入到可执行文件中,这些符号针对使用gdb我使用的 GNU 调试器进行了优化(或者,您可以-glldb使用LLVM/clang 的lldb调试器,或者只是-g用于一般调试符号,但这不会像-ggdb表面上那么好......)。然而,我最近偶然发现有人说使用-Og(而不是-O0),这让我措手不及。果然,它在man gcc!:

-Og优化调试体验。 -Og启用不干扰调试的优化。它应该是标准编辑-编译-调试周期的优化级别选择,提供合理的优化级别,同时保持快速编译和良好的调试体验。

那么,有什么区别呢?这是-O0来自的描述man gcc

-O0减少编译时间并使调试产生预期结果。这是默认设置。

man gcc不过,明确表示-Og“应该是标准编辑-编译-调试周期选择的优化级别”。

这听起来像是-O0真正的“没有优化”,而-Og“进行了一些优化,但只是那些不干扰调试的优化”。它是否正确?那么,我应该使用哪个,为什么?

有关的:

  1. 相关,但不重复!(仔细阅读,它根本不重复):-O0 、-O1 和 -g 之间有什么区别
  2. 我对--copt=与 Bazel 一起使用的调试设置的回答:gdb:当前上下文中没有符号“i”

c c++ debugging gdb compiler-optimization

10
推荐指数
1
解决办法
5379
查看次数

如何关闭GCC中的所有优化

如何关闭GCC中的所有优化?使用-O0不起作用,因为它仍然优化了没有效果的语句,或者在没有任何break语句的无限循环之后的任何代码.

c gcc compiler-optimization

9
推荐指数
1
解决办法
1341
查看次数