Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在不带btsl指令的情况下使用内联asm设置位_C_Assembly_Gcc_X86_Inline Assembly - Fatal编程技术网

C 在不带btsl指令的情况下使用内联asm设置位

C 在不带btsl指令的情况下使用内联asm设置位,c,assembly,gcc,x86,inline-assembly,C,Assembly,Gcc,X86,Inline Assembly,我想在p位置设置一个位,而不使用btsl指令和内联asm gcc c代码。使用btsl指令很简单: int n,p; scanf("%d%d",&n,&p); asm("btsl %1, %0" :"=m"(n) :"Ir"(p) :"cc"); 我知道设置位可以做到: n|=1<<p; 在我看来,shl指令不起作用。例如,n=20=10100。当我尝试设置第一位p

我想在p位置设置一个位,而不使用btsl指令和内联asm gcc c代码。使用btsl指令很简单:

int n,p;
scanf("%d%d",&n,&p);
asm("btsl %1, %0"
:"=m"(n)
:"Ir"(p)
:"cc");
我知道设置位可以做到:

n|=1<<p;

在我看来,shl指令不起作用。例如,n=20=10100。当我尝试设置第一位p=1时,结果是22=10110,而不是21=10101。下面是Michael的示例,我已经完成了清除和切换以及设置:

unsigned long bitset(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "or %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}


unsigned long bitclear(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "not %[tempreg]\n\t"
         "and %[tempreg], %[val]\n\t"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}
unsigned long toggle(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "xor %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}

另外,shl$1、%%ebx并没有做您认为它能做的事情。它通过
1
移动
ebx
,而不是通过
ebx
移动
1
。注意:不要在内联asm中使用
mov
,而只使用适当的约束。您已经为
p
指定了
b
作为输入,因此编译器已经将其放入
ebx
。所以
movl%2,%%ebx
只是扩展到一个无意义的
movl%ebx,%ebx
。与
n
相同。您忘记将
%eax
也指定为输出/关闭器。请注意,您将
eax
指定为输入寄存器,但随后继续覆盖它。这是不允许的。如果将其指定为输出(或clobber,但如果它已经是输入,则不支持此操作),则可以覆盖它。您的代码实际上应该只包含
shl
,并对输入和输出使用约束。除了
shl
之外,为什么在每条指令上都使用冗余的
l
操作数大小后缀?不管怎么说,没什么关系,我觉得用内联asm做这件事没有任何意义。只需编译
x |=1 btsl有什么问题?如果你的CPU坏了,你应该更换CPU。你为什么要用EBX呢?那是毫无意义的。以
mov
指令开始和结束也是毫无意义的,只需告诉编译器您将内容放在正确的寄存器中,并要求它以正确的寄存器开始(即ECX中的计数)。而且,这是一个错误:您编写ECX时没有声明一个clobber。(对该错误投了反对票;内联asm很难正确使用,不会出现使用错误的危险示例。如果您将其简化为“必需”的3条指令,或者如果您只是使其安全但仍然是低效的垃圾,我很乐意将其删除。)如果您真的打算使用这3条指令(mov/shl/or)然后你可以这样做:bitclear仍然只需要3条指令;你可以旋转
0xFFFFFFFE
把零放在你想要的地方。@Peter Cordes,你能写下这个例子吗?我从来没有见过这样的方法来清除。
unsigned long bitset(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "or %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}


unsigned long bitclear(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "not %[tempreg]\n\t"
         "and %[tempreg], %[val]\n\t"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}
unsigned long toggle(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "xor %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}