diff --git a/src/CppAst.Tests/TestStructs.cs b/src/CppAst.Tests/TestStructs.cs index 2bfebf7..0810837 100644 --- a/src/CppAst.Tests/TestStructs.cs +++ b/src/CppAst.Tests/TestStructs.cs @@ -310,5 +310,46 @@ struct HelloWorld } ); } + + [Test] + public void TestBitOffsets() + { + ParseAssert(@" +struct NormalFields +{ + int a; + short b; + float c; +}; + +struct Bitfields +{ + int a : 1; + int b : 2; + int c : 3; +}; +", + compilation => + { + Assert.False(compilation.HasErrors); + + void Test(int classIndex, int fieldIndex, int expectedOffset, int expectedBitOffset) + { + var cppStruct = compilation.Classes[classIndex]; + var field = cppStruct.Fields[fieldIndex]; + Assert.AreEqual(expectedOffset, field.Offset); + Assert.AreEqual(expectedBitOffset, field.BitOffset); + } + + Test(0, 0, 0, 0); + Test(0, 1, 4, 32); + Test(0, 2, 8, 64); + + Test(1, 0, 0, 0); + Test(1, 1, 0, 1); + Test(1, 2, 0, 3); + } + ); + } } } diff --git a/src/CppAst/CppField.cs b/src/CppAst/CppField.cs index 1958c6a..32bbd9a 100644 --- a/src/CppAst/CppField.cs +++ b/src/CppAst/CppField.cs @@ -71,11 +71,16 @@ public CppField(CppType type, string name) /// Gets or sets the number of bits for this bit field. Only valid if is true. /// public int BitFieldWidth { get; set; } - + + /// + /// Gets the offset of the field in bytes. + /// + public long Offset => BitOffset / 8; + /// - /// Gets or sets the offset of the field in bytes. + /// Gets or sets the offset of the field in bits. /// - public long Offset { get; set; } + public long BitOffset { get; set; } /// public override string ToString() diff --git a/src/CppAst/CppModelBuilder.cs b/src/CppAst/CppModelBuilder.cs index ba2ec60..fadb1d3 100644 --- a/src/CppAst/CppModelBuilder.cs +++ b/src/CppAst/CppModelBuilder.cs @@ -531,13 +531,14 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d // Might not be always correct (with alignment rules), // but not sure how to recover the offset without recalculating the entire offsets // BF: disregard the above comment? as we are now aligning using the anonymous struct's AlignOf... - var offset = 0L; + var bitOffset = 0L; var cppClassContainer = containerContext.Container as CppClass; if (cppClassContainer is object && cppClassContainer.Fields.Count > 0) { var lastField = cppClassContainer.Fields[cppClassContainer.Fields.Count - 1]; - offset = (int)lastField.Offset + lastField.Type.SizeOf; + var offset = lastField.Offset + lastField.Type.SizeOf; offset = Align(offset, cppClass.AlignOf); + bitOffset = offset * 8; static long Align(long offset, long alignment) { @@ -551,7 +552,7 @@ static long Align(long offset, long alignment) Visibility = containerContext.CurrentVisibility, StorageQualifier = GetStorageQualifier(cursor), IsAnonymous = true, - Offset = offset, + BitOffset = bitOffset, }; ParseAttributes(cursor, cppField, true); containerContext.DeclarationContainer.Fields.Add(cppField); @@ -1154,7 +1155,7 @@ private CppField VisitFieldOrVariable(CppContainerContext containerContext, CXCu cppField = previousField; cppField.Name = fieldName; cppField.Type = type; - cppField.Offset = cursor.OffsetOfField / 8; + cppField.BitOffset = cursor.OffsetOfField; } else { @@ -1164,7 +1165,7 @@ private CppField VisitFieldOrVariable(CppContainerContext containerContext, CXCu StorageQualifier = GetStorageQualifier(cursor), IsBitField = cursor.IsBitField, BitFieldWidth = cursor.FieldDeclBitWidth, - Offset = cursor.OffsetOfField / 8, + BitOffset = cursor.OffsetOfField, }; containerContext.DeclarationContainer.Fields.Add(cppField); ParseAttributes(cursor, cppField, true); @@ -1188,7 +1189,7 @@ private void AddAnonymousTypeWithField(CppContainerContext containerContext, CXC Visibility = GetVisibility(cursor.CXXAccessSpecifier), StorageQualifier = GetStorageQualifier(cursor), IsAnonymous = true, - Offset = cursor.OffsetOfField / 8, + BitOffset = cursor.OffsetOfField, }; containerContext.DeclarationContainer.Fields.Add(cppField); ParseAttributes(cursor, cppField, true);