The OFFSETOF() macro in C++
The C Standard Library offers the offsetof() macro in C++, that allows you to determine the offset of a specific member in bytes inside a structure or class. It's especially helpful when working with data structures and low-level programming when determining the precise location of a member variable. When using offsetof(), you usually need to specify the name of the member whose offset you want to find and the type of structure or class. A constant expression of type size_t containing the offset is returned by the macro.
Syntax:
It has the following syntax:
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
The address of the necessary element is accessed and cast to size_t, and zero is cast to the type of structure. According to convention, size_t is an unsigned int. The number of bytes that the ELEMENT is inserted into the structure after is determined by the overall expression. As an illustration, the code below returns 16 bytes (padding is taken into account on 32-bit machines) as the character variable c's displacement within the Pod structure.
C++ Code:
#include <iostream>
#include <cstddef>
struct MyStruct {
int a;
char b;
double c;
};
int main() {
size_t offsetOfB = offsetof(MyStruct, b);
std::cout << "Offset of member 'b' in MyStruct: " << offsetOfB << " bytes" << std::endl;
// You can use the offset for various purposes, such as accessing the member indirectly
MyStruct instance;
*reinterpret_cast<char*>(&instance + offsetOfB) = 'X';
std::cout << "Value of member 'b' after modification: " << instance.b << std::endl;
return 0;
}
Output:
Offset of member 'b' in MyStruct: 4 bytes
Value of member 'b' after modification:
Example 2:
Let us take an example to illustrate the use of the offsetof macro() function in C++:
#include <iostream>
#include <cstddef>
struct Employee {
int employeeId;
char name[50];
double salary;
};
int main() {
// Create an array of employees
Employee employees[] = {
{1, "Alice", 50000.0},
{2, "Bob", 60000.0},
{3, "Charlie", 75000.0}
};
// Calculate the offset of the 'name' member within the Employee structure
size_t offsetOfName = offsetof(Employee, name);
// Print the names of the employees using the offset
for (const auto& emp : employees) {
const char* employeeName = reinterpret_cast<const char*>(&emp) + offsetOfName;
std::cout << "Employee Name: " << employeeName << std::endl;
}
return 0;
}
Output:
Employee Name: Alice
Employee Name: Bob
Employee Name: Charlie
Example 3:
Let us take another example to illustrate the use of the offsetof macro() function in C++:
#include <iostream>
#include <cstddef>
struct Address {
char street[50];
char city[30];
int zipCode;
};
struct Person {
int personId;
char name[50];
Address address;
double salary;
};
int main() {
// Create an array of persons
Person people[] = {
{101, "John Doe", {"123 Main St", "Anytown", 12345}, 60000.0},
{102, "Jane Smith", {"456 Oak St", "Othercity", 67890}, 70000.0},
// Add more persons if needed
};
// Calculate the offset of the 'address' member within the Person structure
size_t offsetOfAddress = offsetof(Person, address);
// Print the cities of the people using the offset
for (const auto& person : people) {
const char* city = reinterpret_cast<const char*>(&person) + offsetOfAddress + offsetof(Address, city);
std::cout << "City: " << city << std::endl;
}
return 0;
}
Output:
City: Anytown
City: Othercity
Example 4:
Let us take another example to illustrate the use of the offsetof macro() function in C++:
#include <iostream>
#include <cstddef>
class Shape {
public:
virtual void draw() const {
std::cout << "Drawing a generic shape." << std::endl;
}
virtual ~Shape() {}
};
class Circle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a circle." << std::endl;
}
double radius;
};
int main() {
size_t offsetOfRadius = offsetof(Circle, radius);
std::cout << "Offset of member 'radius' in Circle: " << offsetOfRadius << " bytes" << std::endl
// Use the offset for some purpose
return 0;
}
Output:
Offset of member 'radius' in Circle: 8 bytes
Conclusion:
For low-level programming tasks, the offsetof() macro in C++ is a useful tool because it allows one to determine the offset, in bytes, of a specific member within a structure or class. This feature is especially helpful when working with memory layouts and data structures, where exact member position knowledge is essential. Although the offsetof() function gives developers access to specific members and allows for direct memory manipulation, its use needs to be carefully considered. Because the precise memory layout varies between platforms and compilers, developers should be careful when working with polymorphic types or classes that contain virtual functions. Using member access operators improves readability, type safety, and portability in modern C++ programming.