@@ -174,7 +174,8 @@ layout such as reinterpreting values as a different type.
174
174
Because of this dual purpose, it is possible to create types that are not useful
175
175
for interfacing with the C programming language.
176
176
177
- This representation can be applied to structs, unions, and enums.
177
+ This representation can be applied to structs, unions, and enums. The exception
178
+ is [ zero-variant enums] for which the ` C ` representation is an error.
178
179
179
180
#### \# [ repr(C)] Structs
180
181
@@ -273,9 +274,9 @@ assert_eq!(std::mem::size_of::<SizeRoundedUp>(), 8); // Size of 6 from b,
273
274
assert_eq! (std :: mem :: align_of :: <SizeRoundedUp >(), 4 ); // From a
274
275
```
275
276
276
- #### \# [ repr(C)] Enums
277
+ #### \# [ repr(C)] Field-less Enums
277
278
278
- For [ C-like enumerations ] , the ` C ` representation has the size and alignment of
279
+ For [ field-less enums ] , the ` C ` representation has the size and alignment of
279
280
the default ` enum ` size and alignment for the target platform's C ABI.
280
281
281
282
> Note: The enum representation in C is implementation defined, so this is
@@ -285,40 +286,216 @@ the default `enum` size and alignment for the target platform's C ABI.
285
286
<div class =" warning " >
286
287
287
288
Warning: There are crucial differences between an ` enum ` in the C language and
288
- Rust's C-like enumerations with this representation. An ` enum ` in C is
289
+ Rust's [ field-less enums ] with this representation. An ` enum ` in C is
289
290
mostly a ` typedef ` plus some named constants; in other words, an object of an
290
291
` enum ` type can hold any integer value. For example, this is often used for
291
- bitflags in ` C ` . In contrast, Rust’s C-like enumerations can only legally hold
292
- the discriminant values, everything else is undefined behaviour . Therefore,
293
- using a C-like enumeration in FFI to model a C ` enum ` is often wrong.
292
+ bitflags in ` C ` . In contrast, Rust’s [ field-less enums ] can only legally hold
293
+ the discrimnant values, everything else is [ undefined behavior ] . Therefore,
294
+ using a field-less enum in FFI to model a C ` enum ` is often wrong.
294
295
295
296
</div >
296
297
297
- It is an error for [ zero-variant enumerations ] to have the ` C ` representation.
298
+ #### \# [ repr(C) ] Enums With Fields
298
299
299
- For all other enumerations, the layout is unspecified.
300
+ The representation of a ` repr(C) ` enum with fields is a ` repr(C) ` struct with
301
+ two fields, also called a "tagged union" in C:
300
302
301
- Likewise, combining the ` C ` representation with a primitive representation, the
302
- layout is unspecified.
303
+ - a ` repr(C) ` version of the enum with all fields removed ("the tag")
304
+ - a ` repr(C) ` union of ` repr(C) ` structs for the fields of each variant that had
305
+ them ("the payload")
306
+
307
+ > Note: Due to the representation of ` repr(C) ` structs and unions, if a variant
308
+ > has a single field there is no difference between putting that field directly
309
+ > in the union or wrapping it in a struct; any system which wishes to manipulate
310
+ > such an ` enum ` 's representation may therefore use whichever form is more
311
+ > convenient or consistent for them.
312
+
313
+ ``` rust
314
+ // This Enum has the same representation as ...
315
+ #[repr(C )]
316
+ enum MyEnum {
317
+ A (u32 ),
318
+ B (f32 , u64 ),
319
+ C { x : u32 , y : u8 },
320
+ D ,
321
+ }
322
+
323
+ // ... this struct.
324
+ #[repr(C )]
325
+ struct MyEnumRepr {
326
+ tag : MyEnumDiscriminant ,
327
+ payload : MyEnumFields ,
328
+ }
329
+
330
+ // This is the discriminant enum.
331
+ #[repr(C )]
332
+ enum MyEnumDiscriminant { A , B , C , D }
333
+
334
+ // This is the variant union.
335
+ #[repr(C )]
336
+ union MyEnumFields {
337
+ A : MyAFields ,
338
+ B : MyBFields ,
339
+ C : MyCFields ,
340
+ D : MyDFields ,
341
+ }
342
+
343
+ #[repr(C )]
344
+ #[derive(Copy , Clone )]
345
+ struct MyAFields (u32 );
346
+
347
+ #[repr(C )]
348
+ #[derive(Copy , Clone )]
349
+ struct MyBFields (f32 , u64 );
350
+
351
+ #[repr(C )]
352
+ #[derive(Copy , Clone )]
353
+ struct MyCFields { x : u32 , y : u8 }
354
+
355
+ // This struct could be omitted (it is a zero-sized type), and it must be in
356
+ // C/C++ headers.
357
+ #[repr(C )]
358
+ #[derive(Copy , Clone )]
359
+ struct MyDFields ;
360
+ ```
361
+
362
+ > Note: ` union ` s with non-` Copy ` fields are unstable, see [ 55149] .
303
363
304
364
### Primitive representations
305
365
306
366
The * primitive representations* are the representations with the same names as
307
367
the primitive integer types. That is: ` u8 ` , ` u16 ` , ` u32 ` , ` u64 ` , ` u128 ` ,
308
368
` usize ` , ` i8 ` , ` i16 ` , ` i32 ` , ` i64 ` , ` i128 ` , and ` isize ` .
309
369
310
- Primitive representations can only be applied to enumerations.
370
+ Primitive representations can only be applied to enumerations and have
371
+ different behavior whether the enum has fields or no fields. It is an error
372
+ for [ zero-variant enumerations] to have a primitive representation. Combining
373
+ two primitive representations together is an error.
374
+
375
+ #### Primitive Representation of Field-less Enums
376
+
377
+ For [ field-less enums] , primitive representations set the size and alignment to
378
+ be the same as the primitive type of the same name. For example, a field-less
379
+ enum with a ` u8 ` representation can only have discriminants between 0 and 255
380
+ inclusive.
311
381
312
- For [ C-like enumerations] , they set the size and alignment to be the same as the
313
- primitive type of the same name. For example, a C-like enumeration with a ` u8 `
314
- representation can only have discriminants between 0 and 255 inclusive.
382
+ #### Primitive Representation of Enums With Fields
315
383
316
- It is an error for [ zero-variant enumerations] to have a primitive
317
- representation.
384
+ The representation of a primitive representation enum is a ` repr(C) ` union of
385
+ ` repr(C) ` structs for each variant with a field. The first field of each struct
386
+ in the union is the primitive representation version of the enum with all fields
387
+ removed ("the tag") and the remaining fields are the fields of that variant.
318
388
319
- For all other enumerations, the layout is unspecified.
389
+ > Note: This representation is unchanged if the tag is given its own member in
390
+ > the union, should that make manipulation more clear for you (although to
391
+ > follow the C++ standard the tag member should be wrapped in a ` struct ` ).
392
+
393
+ ``` rust
394
+ // This enum has the same representation as ...
395
+ #[repr(u8 )]
396
+ enum MyEnum {
397
+ A (u32 ),
398
+ B (f32 , u64 ),
399
+ C { x : u32 , y : u8 },
400
+ D ,
401
+ }
402
+
403
+ // ... this union.
404
+ #[repr(C )]
405
+ union MyEnumRepr {
406
+ A : MyVariantA ,
407
+ B : MyVariantB ,
408
+ C : MyVariantC ,
409
+ D : MyVariantD ,
410
+ }
411
+
412
+ // This is the discriminant enum.
413
+ #[repr(u8 )]
414
+ #[derive(Copy , Clone )]
415
+ enum MyEnumDiscriminant { A , B , C , D }
416
+
417
+ #[repr(C )]
418
+ #[derive(Clone , Copy )]
419
+ struct MyVariantA (MyEnumDiscriminant , u32 );
420
+
421
+ #[repr(C )]
422
+ #[derive(Clone , Copy )]
423
+ struct MyVariantB (MyEnumDiscriminant , f32 , u64 );
424
+
425
+ #[repr(C )]
426
+ #[derive(Clone , Copy )]
427
+ struct MyVariantC { tag : MyEnumDiscriminant , x : u32 , y : u8 }
428
+
429
+ #[repr(C )]
430
+ #[derive(Clone , Copy )]
431
+ struct MyVariantD (MyEnumDiscriminant );
432
+ ```
433
+
434
+ > Note: ` union ` s with non-` Copy ` fields are unstable, see [ 55149] .
435
+
436
+ #### Combining primitive representations of enums with fields and \# [ repr(C)]
437
+
438
+ For enums with fields, it is also possible to combine ` repr(C) ` and a
439
+ primitive representation (e.g., ` repr(C, u8) ` ). This modifies the [ ` repr(C) ` ] by
440
+ changing the representation of the discriminant enum to the chosen primitive
441
+ instead. So, if you chose the ` u8 ` representation, then the discriminant enum
442
+ would have a size and alignment of 1 byte.
443
+
444
+ The discriminant enum from the example [ earlier] [ `repr(C)` ] then becomes:
445
+
446
+ ``` rust
447
+ #[repr(C , u8 )] // `u8` was added
448
+ enum MyEnum {
449
+ A (u32 ),
450
+ B (f32 , u64 ),
451
+ C { x : u32 , y : u8 },
452
+ D ,
453
+ }
454
+
455
+ // ...
456
+
457
+ #[repr(u8 )] // So `u8` is used here instead of `C`
458
+ enum MyEnumDiscriminant { A , B , C , D }
459
+
460
+ // ...
461
+ ```
462
+
463
+ For example, with a ` repr(C, u8) ` enum it is not possible to have 257 unique
464
+ discriminants ("tags") whereas the same enum with only a ` repr(C) ` attribute
465
+ will compile without any problems.
466
+
467
+ Using a primitive representation in addition to ` repr(C) ` can change the size of
468
+ an enum from the ` repr(C) ` form:
469
+
470
+ ``` rust
471
+ #[repr(C )]
472
+ enum EnumC {
473
+ Variant0 (u8 ),
474
+ Variant1 ,
475
+ }
476
+
477
+ #[repr(C , u8 )]
478
+ enum Enum8 {
479
+ Variant0 (u8 ),
480
+ Variant1 ,
481
+ }
482
+
483
+ #[repr(C , u16 )]
484
+ enum Enum16 {
485
+ Variant0 (u8 ),
486
+ Variant1 ,
487
+ }
488
+
489
+ // The size of the C representation is platform dependant
490
+ assert_eq! (std :: mem :: size_of :: <EnumC >(), 8 );
491
+ // One byte for the discriminant and one byte for the value in Enum8::Variant0
492
+ assert_eq! (std :: mem :: size_of :: <Enum8 >(), 2 );
493
+ // Two bytes for the discriminant and one byte for the value in Enum16::Variant0
494
+ // plus one byte of padding.
495
+ assert_eq! (std :: mem :: size_of :: <Enum16 >(), 4 );
496
+ ```
320
497
321
- Likewise, combining two primitive representations together is unspecified.
498
+ [ `repr(C)` ] : #reprc-enums-with-fields
322
499
323
500
### The alignment modifiers
324
501
@@ -379,12 +556,14 @@ used with any other representation.
379
556
[ `align_of` ] : ../std/mem/fn.align_of.html
380
557
[ `size_of` ] : ../std/mem/fn.size_of.html
381
558
[ `Sized` ] : ../std/marker/trait.Sized.html
559
+ [ `Copy` ] : ../std/marker/trait.Copy.html
382
560
[ dynamically sized types ] : dynamically-sized-types.md
383
- [ C-like enumerations ] : items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations
561
+ [ field-less enums ] : items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations
384
562
[ enumerations ] : items/enumerations.md
385
- [ zero-variant enumerations ] : items/enumerations.md#zero-variant-enums
563
+ [ zero-variant enums ] : items/enumerations.md#zero-variant-enums
386
564
[ undefined behavior ] : behavior-considered-undefined.md
387
565
[ 27060 ] : https://github.com/rust-lang/rust/issues/27060
566
+ [ 55149 ] : https://github.com/rust-lang/rust/issues/55149
388
567
[ `PhantomData<T>` ] : special-types-and-traits.md#phantomdatat
389
568
[ Default ] : #the-default-representation
390
569
[ `C` ] : #the-c-representation
0 commit comments