panzerQ
光坂国中生
光坂国中生
  • 注册日期2026-03-15
  • 最后登录2026-06-22
  • 生日2004-1-1
  • 光玉10颗
阅读:195回复:3

合理使用逻辑短路

楼主#
更多 发布于:2026-05-07 11:16
这里主要说说类C语言中的逻辑与。
为了防止踩到空指针,你可以这样写:

if (ptr && *ptr ... ) { }
如果前面的ptr是空指针,就不会再去访问ptr指向的内存。

不过,这种便利可能是有代价的,
当你不需要使用短路特性时,你也可以这样写:

if (A_True & B_True) { }
做完按位与,判断是否为0,直觉上很贴汇编。

LLM认为后者的性能比逻辑与更好,
这里还缺一个实机测试环节,未来有空给补上。
喜欢0 评分0
panzerQ
光坂国中生
光坂国中生
  • 注册日期2026-03-15
  • 最后登录2026-06-22
  • 生日2004-1-1
  • 光玉10颗
沙发#
发布于:2026-05-14 11:22
对应的汇编也放一下吧,
万一有绅士喜欢看呢?
(迎合绅士的喜好,没采用等宽字体)

       .file        "CTest.c"
        .text
        .p2align 4
        .def        printf;        .scl        3;        .type        32;        .endef
        .seh_proc        printf
printf:
        pushq        %rsi
        .seh_pushreg        %rsi
        pushq        %rbx
        .seh_pushreg        %rbx
        subq        $56, %rsp
        .seh_stackalloc        56
        .seh_endprologue
        leaq        88(%rsp), %rsi
        movq        %rcx, %rbx
        movq        %rdx, 88(%rsp)
        movl        $1, %ecx
        movq        %r8, 96(%rsp)
        movq        %r9, 104(%rsp)
        movq        %rsi, 40(%rsp)
        call        *__imp___acrt_iob_func(%rip)
        movq        %rsi, %r8
        movq        %rbx, %rdx
        movq        %rax, %rcx
        call        __mingw_vfprintf
        addq        $56, %rsp
        popq        %rbx
        popq        %rsi
        ret
        .seh_endproc
        .p2align 4
        .def        get_time_ns;        .scl        3;        .type        32;        .endef
        .seh_proc        get_time_ns
get_time_ns:
        subq        $56, %rsp
        .seh_stackalloc        56
        .seh_endprologue
        leaq        32(%rsp), %rcx
        call        *__imp_QueryPerformanceFrequency(%rip)
        leaq        40(%rsp), %rcx
        call        *__imp_QueryPerformanceCounter(%rip)
        imulq        $1000000000, 40(%rsp), %rax
        cqto
        idivq        32(%rsp)
        addq        $56, %rsp
        ret
        .seh_endproc
        .section .rdata,"dr"
        .align 8
.LC0:
        .ascii "Logical AND - dummy count: %d\12\0"
        .text
        .p2align 4
        .globl        test_logical_and
        .def        test_logical_and;        .scl        2;        .type        32;        .endef
        .seh_proc        test_logical_and
test_logical_and:
        pushq        %rsi
        .seh_pushreg        %rsi
        pushq        %rbx
        .seh_pushreg        %rbx
        subq        $56, %rsp
        .seh_stackalloc        56
        .seh_endprologue
        movl        $100000000, %esi
        movl        $0, 44(%rsp)
        .p2align 4,,10
        .p2align 3
.L6:
        call        rand
        movl        %eax, %ebx
        call        rand
        andl        $1, %ebx
        je        .L5
        testb        $1, %al
        je        .L5
        movl        44(%rsp), %eax
        addl        $1, %eax
        movl        %eax, 44(%rsp)
.L5:
        subq        $1, %rsi
        jne        .L6
        movl        44(%rsp), %edx
        leaq        .LC0(%rip), %rcx
        addq        $56, %rsp
        popq        %rbx
        popq        %rsi
        jmp        printf
        .seh_endproc
        .section .rdata,"dr"
        .align 8
.LC1:
        .ascii "Bitwise  AND - dummy count: %d\12\0"
        .text
        .p2align 4
        .globl        test_bitwise_and
        .def        test_bitwise_and;        .scl        2;        .type        32;        .endef
        .seh_proc        test_bitwise_and
test_bitwise_and:
        pushq        %rsi
        .seh_pushreg        %rsi
        pushq        %rbx
        .seh_pushreg        %rbx
        subq        $56, %rsp
        .seh_stackalloc        56
        .seh_endprologue
        movl        $100000000, %esi
        movl        $0, 44(%rsp)
        .p2align 4,,10
        .p2align 3
.L16:
        call        rand
        movl        %eax, %ebx
        call        rand
        movl        %ebx, %edx
        shrl        $31, %edx
        addl        %edx, %ebx
        andl        $1, %ebx
        subl        %edx, %ebx
        movl        %eax, %edx
        shrl        $31, %edx
        addl        %edx, %eax
        andl        $1, %eax
        subl        %edx, %eax
        testl        %eax, %ebx
        je        .L15
        movl        44(%rsp), %eax
        addl        $1, %eax
        movl        %eax, 44(%rsp)
.L15:
        subq        $1, %rsi
        jne        .L16
        movl        44(%rsp), %edx
        leaq        .LC1(%rip), %rcx
        addq        $56, %rsp
        popq        %rbx
        popq        %rsi
        jmp        printf
        .seh_endproc
        .def        __main;        .scl        2;        .type        32;        .endef
        .section .rdata,"dr"
.LC3:
        .ascii "Logical && elapsed: %.2f ms\12\12\0"
.LC4:
        .ascii "Bitwise  & elapsed: %.2f ms\12\0"
        .section        .text.startup,"x"
        .p2align 4
        .globl        main
        .def        main;        .scl        2;        .type        32;        .endef
        .seh_proc        main
main:
        pushq        %rbx
        .seh_pushreg        %rbx
        subq        $48, %rsp
        .seh_stackalloc        48
        movaps        %xmm6, 32(%rsp)
        .seh_savexmm        %xmm6, 32
        .seh_endprologue
        call        __main
        xorl        %ecx, %ecx
        call        *__imp__time64(%rip)
        movl        %eax, %ecx
        call        srand
        call        get_time_ns
        movq        %rax, %rbx
        call        test_logical_and
        call        get_time_ns
        pxor        %xmm1, %xmm1
        movsd        .LC2(%rip), %xmm6
        leaq        .LC3(%rip), %rcx
        subq        %rbx, %rax
        cvtsi2sdq        %rax, %xmm1
        divsd        %xmm6, %xmm1
        movq        %xmm1, %rdx
        call        printf
        call        get_time_ns
        movq        %rax, %rbx
        call        test_bitwise_and
        call        get_time_ns
        pxor        %xmm1, %xmm1
        leaq        .LC4(%rip), %rcx
        subq        %rbx, %rax
        cvtsi2sdq        %rax, %xmm1
        divsd        %xmm6, %xmm1
        movq        %xmm1, %rdx
        call        printf
        nop
        movaps        32(%rsp), %xmm6
        xorl        %eax, %eax
        addq        $48, %rsp
        popq        %rbx
        ret
        .seh_endproc
        .section .rdata,"dr"
        .align 8
.LC2:
        .long        0
        .long        1093567616
        .ident        "GCC: (x86_64-win32-seh-rev1, Built by MinGW-W64 project) 12.2.0"
        .def        __mingw_vfprintf;        .scl        2;        .type        32;        .endef
        .def        rand;        .scl        2;        .type        32;        .endef
        .def        srand;        .scl        2;        .type        32;        .endef
回复(0) 喜欢(0)     评分
panzerQ
光坂国中生
光坂国中生
  • 注册日期2026-03-15
  • 最后登录2026-06-22
  • 生日2004-1-1
  • 光玉10颗
2楼#
发布于:2026-05-14 11:18
测试用的机器,情况如下:
OS: Win11 25H2
RAM: 16+16 DDR4
CPU: AMD Ryzen5 4600G @ 3.70GHz

使用MinGW提供的GCC 12编译,
开启O2优化,std=C11

后台没有大负载,
在1e8次循环后,
典型的打印结果:
Logical AND - dummy count: 24999945
Logical && elapsed: 2731.92 ms

Bitwise  AND - dummy count: 24999990
Bitwise  & elapsed: 2531.15 ms


哦豁,看起来这次是LLM说对了......
回复(0) 喜欢(0)     评分
panzerQ
光坂国中生
光坂国中生
  • 注册日期2026-03-15
  • 最后登录2026-06-22
  • 生日2004-1-1
  • 光玉10颗
3楼#
发布于:2026-05-14 11:15
有空了,遂Vibe Coding一个测试用的玩具,
我不是真的专家,但我觉得设计还算合理,
源码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>

static inline long long get_time_ns() {
    LARGE_INTEGER freq, count;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&count);
    return count.QuadPart * 1000000000LL / freq.QuadPart;
}

#define ITERATIONS 100000000LL

// short-circuit evaluation
void test_logical_and(void) {
    volatile int dummy = 0;
    for (long long i = 0; i < ITERATIONS; ++i) {
        int a = rand();
        int b = rand();
        if ((a % 2) && (b % 2))
            dummy++;
    }
    printf("Logical AND - dummy count: %d\n", dummy);
}

// non-short-circuit evaluation
void test_bitwise_and(void) {
    volatile int dummy = 0;
    for (long long i = 0; i < ITERATIONS; ++i) {
        int a = rand();
        int b = rand();
        if ((a % 2) & (b % 2))
            dummy++;
    }
    printf("Bitwise  AND - dummy count: %d\n", dummy);
}

int main() {
    srand((unsigned int)time(NULL));

    long long start, end;
    double time_ms;

    // Benchmark Logical AND
    start = get_time_ns();
    test_logical_and();
    end = get_time_ns();
    time_ms = (end - start) / 1000000.0;
    printf("Logical && elapsed: %.2f ms\n\n", time_ms);

    // Benchmark Bitwise AND
    start = get_time_ns();
    test_bitwise_and();
    end = get_time_ns();
    time_ms = (end - start) / 1000000.0;
    printf("Bitwise  & elapsed: %.2f ms\n", time_ms);

    return 0;
}
回复(0) 喜欢(0)     评分
游客

返回顶部