Skip to content

Commit bd644d2

Browse files
committed
Added mdbook entry for bitfields.
1 parent c160b20 commit bd644d2

File tree

2 files changed

+197
-0
lines changed

2 files changed

+197
-0
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@
1919
- [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
2020
- [Generating Bindings to C++](./cpp.md)
2121
- [Using Unions](./using-unions.md)
22+
- [Using Bitfields](./using-bitfields.md)
2223
- [FAQ](./faq.md)

book/src/using-bitfields.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# Using the Bitfield Types Generated by Bindgen
2+
3+
For this discussion, we will use the following C type definitions and functions.
4+
```c
5+
typedef struct {
6+
unsigned int a: 1;
7+
unsigned int b: 1;
8+
unsigned int c: 2;
9+
10+
} bitfield;
11+
12+
// Create a default bitfield
13+
bitfield create_bitfield();
14+
15+
// Print a bitfield
16+
void print_bitfield(bitfield bfield)
17+
```
18+
19+
Bindgen creates a set of field getters and setters for interacting with the bitset. For example,
20+
21+
```rust,ignore
22+
let mut bfield = unsafe { create_bitfield() };
23+
24+
bfield.set_a(1);
25+
println!("a set to {}", bfield.a());
26+
bfield.set_b(1);
27+
println!("b set to {}", bfield.b());
28+
bfield.set_c(3);
29+
println!("c set to {}", bfield.c());
30+
unsafe { print_bitfield(bfield) };
31+
```
32+
33+
will print out
34+
35+
```text
36+
a set to 1
37+
b set to 1
38+
c set to 3
39+
bitfield: a:1, b:1, c:3
40+
```
41+
42+
Overflowing a bitfield will result in the same behavior as in C/C++: the bitfield will be set to 0.
43+
44+
```rust,ignore
45+
let mut bfield = unsafe { create_bitfield() };
46+
bfield.set_a(1);
47+
bfield.set_b(1);
48+
bfield.set_c(12);
49+
println!("c set to {} due to overflow", bfield.c());
50+
unsafe { print_bitfield(bfield) };
51+
```
52+
53+
will print out
54+
55+
```text
56+
c set to 0 due to overflow
57+
bitfield: a:1, b:1, c:0
58+
```
59+
60+
To create a new bitfield in Rust, use mem::zeroed.
61+
62+
```rust,ignore
63+
let mut bfield = unsafe { mem::zeroed::<bitfield>() };
64+
bfield.set_a(1);
65+
bfield.set_c(2);
66+
unsafe { print_bitfield(bfield) };
67+
```
68+
69+
This will print out
70+
71+
```text
72+
bitfield: a:1, b:0, c:2
73+
```
74+
75+
## Unsigned bitfield gotcha
76+
77+
Special care should be given to handling unsigned bitfields. Let's change 'c' field to an int. C's valid values are now -2, -1, 0, and 1.
78+
79+
```c
80+
typedef struct {
81+
unsigned int a: 1;
82+
unsigned int b: 1;
83+
int c: 2;
84+
85+
} bitfield;
86+
```
87+
88+
Let's now walk the bitfield possibilities in both C and Rust up to the first overflow on each end:
89+
90+
```c
91+
void walk_bitfield() {
92+
bitfield bfield = create_bitfield();
93+
print_bitfield(bfield);
94+
bfield.c = 1;
95+
print_bitfield(bfield);
96+
bfield.c = 2;
97+
print_bitfield(bfield);
98+
bfield.c = 3;
99+
print_bitfield(bfield);
100+
bfield.c = 4;
101+
print_bitfield(bfield);
102+
bfield.c = -1;
103+
print_bitfield(bfield);
104+
bfield.c = -2;
105+
print_bitfield(bfield);
106+
bfield.c = -3;
107+
print_bitfield(bfield);
108+
bfield.c = -4;
109+
print_bitfield(bfield);
110+
}
111+
```
112+
113+
```rust,ignore
114+
fn walk_bitfield() {
115+
let mut bfield = unsafe { mem::zeroed::<bitfield>() };
116+
unsafe { print_bitfield(bfield) };
117+
bfield.set_c(1);
118+
unsafe { print_bitfield(bfield) };
119+
bfield.set_c(2);
120+
unsafe { print_bitfield(bfield) };
121+
bfield.set_c(3);
122+
unsafe { print_bitfield(bfield) };
123+
bfield.set_c(4);
124+
unsafe { print_bitfield(bfield) };
125+
bfield.set_c(-1);
126+
unsafe { print_bitfield(bfield) };
127+
bfield.set_c(-2);
128+
unsafe { print_bitfield(bfield) };
129+
bfield.set_c(-3);
130+
unsafe { print_bitfield(bfield) };
131+
bfield.set_c(-4);
132+
unsafe { print_bitfield(bfield) };
133+
}
134+
```
135+
136+
This produces identical results in C's print function:
137+
138+
```text
139+
Print C walk
140+
bitfield: a:0, b:0, c:0
141+
bitfield: a:0, b:0, c:1
142+
bitfield: a:0, b:0, c:-2
143+
bitfield: a:0, b:0, c:-1
144+
bitfield: a:0, b:0, c:0
145+
bitfield: a:0, b:0, c:-1
146+
bitfield: a:0, b:0, c:-2
147+
bitfield: a:0, b:0, c:1
148+
bitfield: a:0, b:0, c:0
149+
Print Rust walk
150+
bitfield: a:0, b:0, c:0
151+
bitfield: a:0, b:0, c:1
152+
bitfield: a:0, b:0, c:-2
153+
bitfield: a:0, b:0, c:-1
154+
bitfield: a:0, b:0, c:0
155+
bitfield: a:0, b:0, c:-1
156+
bitfield: a:0, b:0, c:-2
157+
bitfield: a:0, b:0, c:1
158+
bitfield: a:0, b:0, c:0
159+
```
160+
161+
However, Bindgen's getter provides different results:
162+
163+
```rust,ignore
164+
fn getter_walk_bitfield() {
165+
let mut bfield = unsafe { mem::zeroed::<bitfield>() };
166+
println!("c set to {}", bfield.c());
167+
bfield.set_c(1);
168+
println!("c set to {}", bfield.c());
169+
bfield.set_c(2);
170+
println!("c set to {}", bfield.c());
171+
bfield.set_c(3);
172+
println!("c set to {}", bfield.c());
173+
bfield.set_c(4);
174+
println!("c set to {}", bfield.c());
175+
bfield.set_c(-1);
176+
println!("c set to {}", bfield.c());
177+
bfield.set_c(-2);
178+
println!("c set to {}", bfield.c());
179+
bfield.set_c(-3);
180+
println!("c set to {}", bfield.c());
181+
bfield.set_c(-4);
182+
println!("c set to {}", bfield.c());
183+
}
184+
```
185+
186+
```text
187+
c set to 0
188+
c set to 1
189+
c set to 2
190+
c set to 3
191+
c set to 0
192+
c set to 3
193+
c set to 2
194+
c set to 1
195+
c set to 0
196+
```

0 commit comments

Comments
 (0)