Clang-Reorder-Fields¶
clang-reorder-fields is a refactoring tool to reorder fields in C/C++ structs and classes. This tool automatically updates:
Field declarations in the record definition
Constructor initializer lists in C++ classes
Aggregate initialization expressions (both C and C++)
Designated initializer lists (C++20)
This can be useful for optimizing memory layout, improving cache performance, or conforming to coding standards that require specific field orderings.
Example usage¶
Basic struct reordering¶
Consider this simple struct in example.c:
struct Foo {
const int *x;
int y;
double z;
int w;
};
int main() {
const int val = 42;
struct Foo foo = { &val, 0, 1.5, 17 };
return 0;
}
To reorder the fields to z, w, y, x, run:
clang-reorder-fields -record-name Foo -fields-order z,w,y,x example.c --
This will reorder both the struct definition and the initialization:
struct Foo {
double z;
int w;
int y;
const int *x;
};
int main() {
const int val = 42;
struct Foo foo = { 1.5, 17, 0, &val };
return 0;
}
Namespaced structs¶
For C++ code with namespaces, use the fully-qualified name:
namespace bar {
struct Foo {
const int *x;
int y;
double z;
int w;
};
}
clang-reorder-fields -record-name ::bar::Foo -fields-order z,w,y,x example.cpp --
For classes defined in the global namespace (without any namespace), you can use either the simple class name or prefix it with :::
clang-reorder-fields -record-name Foo -fields-order z,w,y,x example.cpp --
# or
clang-reorder-fields -record-name ::Foo -fields-order z,w,y,x example.cpp --
C++ constructor initializer lists¶
The tool also reorders constructor initializer lists. Given:
class Foo {
public:
Foo();
private:
int x;
const char *s1;
const char *s2;
double z;
};
Foo::Foo():
x(12),
s1("abc"),
s2("def"),
z(3.14)
{}
Running:
clang-reorder-fields -record-name Foo -fields-order s1,x,z,s2 example.cpp --
Will reorder both the field declarations and the constructor initializers:
class Foo {
public:
Foo();
private:
const char *s1;
int x;
double z;
const char *s2;
};
Foo::Foo():
s1("abc"),
x(12),
z(3.14),
s2("def")
{}
Designated initializers¶
For C++20 code using designated initializers:
struct Bar {
char a;
int b;
int c;
};
int main() {
Bar bar1 = { 'a', 0, 123 };
Bar bar2 = { .a = 'a', .b = 0, .c = 123 };
return 0;
}
clang-reorder-fields --extra-arg="-std=c++20" -record-name Bar \
-fields-order c,a,b example.cpp --
Will produce:
struct Bar {
int c;
char a;
int b;
};
int main() {
Bar bar1 = { 123, 'a', 0 };
Bar bar2 = { .c = 123, .a = 'a', .b = 0 };
return 0;
}
In-place editing¶
Use the -i flag to modify files in-place:
clang-reorder-fields -record-name Foo -fields-order z,w,y,x -i example.c --
Limitations and Caveats¶
Different access specifiers¶
The tool cannot reorder fields with different access specifiers
(public/private/protected). All fields being reordered must have the same
access level.
class Example {
private:
int x;
public:
int y; // Cannot reorder x and y - different access levels
};
Multiple field declarations¶
Declarations with multiple fields in one statement are not supported:
struct Example {
int a, b; // Not supported - multiple fields in one declaration
};
Macro-expanded fields¶
Macros that expand to multiple field declarations are not supported. However, macros that expand to a single field declaration work correctly:
#define INT_FIELD(NAME) int NAME // Supported - expands to one field
#define TWO_FIELDS int a; int b; // Not supported - expands to two fields
struct Supported {
INT_FIELD(x); // OK - this is a single field
int y;
INT_FIELD(z); // OK - this is a single field
};
struct NotSupported {
TWO_FIELDS // Not OK - expands to multiple fields
int c;
};
The tool can reorder fields declared via macros as long as each macro invocation expands to exactly one field declaration.
Preprocessor directives¶
Structs with preprocessor directives between fields cannot be reordered:
struct Example {
int a;
#ifdef FEATURE
int b;
#endif
int c; // Not supported - preprocessor directives present
};
Flexible array members¶
In C, a flexible array member is an incomplete array type that must be the last member of a struct (as specified by C99 and later standards). This allows the struct to have a variable-length array at the end. Since this is a language requirement, the tool enforces that flexible array members remain in the last position:
struct Example {
int count;
int data[]; // Flexible array member - must remain last
};
Attempting to reorder fields such that the flexible array member is no longer last will result in an error:
clang-reorder-fields -record-name Example -fields-order data,count example.c --
Will produce:
Flexible array member must remain the last field in the struct
This ensures the generated code remains valid C.
Field dependencies in initializers¶
The tool will issue a warning if reordering causes a field to be used in an initializer before it’s initialized. Consider this example:
class Foo {
public:
Foo(int x, char c);
int x;
char c;
Dummy z;
};
Foo::Foo(int x, char c) :
x(x),
c(c),
z(this->x, c) // z's initializer uses x and c
{}
If you reorder the fields to z, c, x:
clang-reorder-fields -record-name Foo -fields-order z,c,x example.cpp --
The tool will produce warnings:
example.cpp:10:3: warning: reordering field x after z makes x uninitialized when used in init expression
example.cpp:10:3: warning: reordering field c after z makes c uninitialized when used in init expression
This warns you that in C++, member initializers are executed in the order that fields are declared in the class, not the order they appear in the initializer list. After reordering, z would be initialized first, but its initializer tries to use x and c which haven’t been initialized yet.
The tool will still perform the reordering but warns about the potential issue. You should review these warnings and adjust your code accordingly.
clang-reorder-fields Command Line Options¶
- --record-name=<string>¶
The fully-qualified name of the struct or class to reorder. Required.
For C structs, use the struct name directly (e.g., Foo).
For C++ classes/structs in namespaces, use the fully-qualified name including namespaces (e.g., ::namespace::ClassName).
For C++ classes/structs in the global namespace, you can use either the simple name (e.g., Foo) or prefix with :: (e.g., ::Foo).
- --fields-order=<string>¶
Comma-separated list of field names in the desired order. Required.
All field names must exactly match the fields in the struct/class definition. The number of fields must match the number in the definition.
- -i¶
Overwrite edited files in-place. If not specified, the rewritten code is printed to stdout.
- --extra-arg=<string>¶
Additional argument to append to the compiler command line.
Useful for specifying language standards (e.g., –extra-arg=”-std=c++20”).
- --extra-arg-before=<string>¶
Additional argument to prepend to the compiler command line.
- -p <string>¶
Build path. Specifies the directory containing compile_commands.json for compilation database support.
Use Cases¶
Memory layout optimization¶
Reorder fields to minimize padding and improve cache locality:
// Before: 24 bytes (with padding)
struct Data {
char a; // 1 byte + 7 padding
double b; // 8 bytes
char c; // 1 byte + 7 padding
};
clang-reorder-fields -record-name Data -fields-order b,a,c data.c --
// After: 16 bytes (less padding)
struct Data {
double b; // 8 bytes
char a; // 1 byte
char c; // 1 byte + 6 padding
};
Coding standard compliance¶
Ensure fields are ordered according to project conventions (e.g., alphabetically, by type, or by access pattern).
Field grouping¶
Group related fields together for better code organization and readability.