我想替换整数中的最低字节.在x86上,这个值正好是mov al, [mem],但是我似乎无法让编译器输出这个值.我是否遗漏了可以识别的明显代码模式,或者我误解了什么,或者这仅仅是遗漏了一个优化?

unsigned insert_1(const unsigned* a, const unsigned char* b)
{
    return (*a & ~255) | *b;
}
unsigned insert_2(const unsigned* a, const unsigned char* b)
{
    return *a >> 8 << 8 | *b;
}

GCC实际上用的是al,但只是用来归零.

        mov     eax, DWORD PTR [rdi]
        movzx   edx, BYTE PTR [rsi]
        xor     al, al
        or      eax, edx
        ret

Clang几乎逐字编译了这两个文件

        mov     ecx, -256
        and     ecx, dword ptr [rdi]
        movzx   eax, byte ptr [rsi]
        or      eax, ecx
        ret

推荐答案

在x86上,这个值正好是mov al, [mem],但是我似乎无法让编译器输出这个值.

试试这个,不用算术:

unsigned insert_4(const unsigned* a, const unsigned char* b)
{
    unsigned int t = *a;
    unsigned char *tcp = (unsigned char *) & t;
    tcp[0] = *b;
    return t;
}


insert_4(unsigned int const*, unsigned char const*):
        mov     eax, DWORD PTR [rdi]
        mov     al, BYTE PTR [rsi]
        ret

我知道这有点奇怪,但编译器很擅长删除局部变量的间接性和地址(尽管做了几次try ).

godbolt x86-64 gcc 13.1 -O3


另一种使用联合的方法是:

unsigned insert_5(const unsigned* a, const unsigned char* b)
{
    union {
        unsigned int ui;
        unsigned char uc;
    } u;
    u.ui = *a;
    u.uc = *b;
    return u.ui;
}

godbolt x86-64 gcc 13.1 -O3


请注意,这些解决方案是特定于字节顺序的,尽管它看起来像是您正在寻找的,并且可以根据需要针对其他字节顺序进行调整.

C++相关问答推荐

如何在不修改字符串缓冲区早期使用的情况下覆盖字符串缓冲区

单指针和空参数列表之间的函数指针兼容性

GLIBC:如何告诉可执行文件链接到特定版本的GLIBC

向上强制转换C中的数值类型总是可逆的吗?

双指针指向常量双指针的指针类型赋值不兼容

在 struct 中强制转换空指针

Linux不想运行编译后的文件

如果dim指定数组中的数据量,使用dim-1会不会潜在地导致丢失一个元素?

在txt文件中找到指定的字符串,并从数字中减go 相同的值

在for循环中指向数组开头之前

C I/O:在Windows控制台上处理键盘输入

在C中创建任意类型的只读指针参数

C将数组传递给函数以修改数组

C程序向服务器发送TCPRST

不确定如何处理此编译错误

强制GCC始终加载常量(即只读),即使启用了优化

如何打印循环调度问题的时间表

未使用sem_open正确初始化信号量

在git补丁中自动添加C的宏

为什么INT_MIN是在c语言的头文件limits.h中定义的(-INT_MAX-1)而不是直接使用-2147483648