私は現在、ロバート・愛のLinuxカーネル開発て読んでいる、第3版、私はclear_bit()
アトミック関数とその非、set_bit()
を説明するセクションの後に奇数の文に遭遇しました-atomic兄弟、__set_bit()
と__clear_bit()
:アトミック整数演算とは異なりプラットフォームに依存しない方法
、コードは、典型的には、特定のビットを設定する唯一の移植可能な方法であるビット演算—を使用するかどうか選択の余地を有していません。
-p。 183(自分の強調)
Iは、これらの操作は、これらのインライン関数が存在する理由である単一のプラットフォーム固有のアセンブリ命令で実装できることを理解します。しかし、私は、著者はこれらがこれらの事を行うにはだけポータブルな方法であることを言った理由として興味があります。これを行うことにより、unsigned long x
で
x |= 1UL << nr;
同様に私ができる非アトミッククリアビットnr
:
x &= ~(1UL << nr);
たとえば、私は非アトミックプレーンなCでこれを行うことにより、
unsigned long x
にビット
nr
を設定することができます信じています
もちろん、コンパイラの洗練度に応じて、これらはいくつかの命令にコンパイルされる可能性がありますので、__set_bit()
と__clear_bit()
の関数ほど良くないかもしれません。
ここに何か不足していますか?このフレーズは、わずかに怠惰な簡素化した、または私はビットをセットしてクリアする上で提示しまし方法について移植何かがあるのでしょうか?
編集:それはGCCはかなり洗練されているが、それはまださえ-O3
(バージョン6.2.1)に、代わりに__set_bit()
機能が行うよう、単一の命令を使用してのビットシフトを行い、ことが表示されます。例として:原子整数演算の文脈において
stephen at greed in ~/code
$ gcc -g -c set.c -O3
stephen at greed in ~/code
$ objdump -d -M intel -S set.o
set.o: file format elf64-x86-64
Disassembly of section .text.startup:
0000000000000000 <main>:
#include<stdio.h>
int main(int argc, char *argv)
{
unsigned long x = 0;
x |= (1UL << argc);
0: 89 f9 mov ecx,edi
2: be 01 00 00 00 mov esi,0x1
7: 48 83 ec 08 sub rsp,0x8
b: 48 d3 e6 shl rsi,cl
e: bf 00 00 00 00 mov edi,0x0
13: 31 c0 xor eax,eax
15: e8 00 00 00 00 call 1a <main+0x1a>
{
1a: 31 c0 xor eax,eax
x |= (1UL << argc);
1c: 48 83 c4 08 add rsp,0x8
printf("x=%x\n", x);
20: c3 ret
あなたは( 'signed')' long'の符号ビットにシフトする場合、これはUBです。 – EOF
フェアポイント - カーネルの操作は 'ボイド*'で定義されているが、私は簡単にするために整数を使用することを決めています。私はそれらを 'unsigned long'に変更します。 – brenns10
編集内容は変更されません。 '1L << nr'は関係なく、あなたは結果を割り当てるどのようなタイプの、署名long'タイプ'で行われます。 – EOF