Clang-Reorder-Fields

clang-reorder-fields is a refactoring tool to reorder fields in C/C++ structs and classes. This tool automatically updates:

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.