Hello everyone!!
I am new to Linux forum and have a question related to typecasting in C related to offset of structures.I have a piece of code and having a problem with this:

void fun(struct c *p)
{
int offset;
struct b *address;
offset=(char *)&((struct c *)(&((struct a*)0)->y)->j)-(char *)((struct a *)0);
address=(struct b *)((char*)&(p->j)-offset);
address->i=400;
address->f=3.14;
address->ch='c';
printf("%u",offset);
}

As you can see that this code is accessible in turbo C but not in Dev C++ and please anybody tell me why is this so and any method to easily typecast structures for finding their offset.

Dani AI

Generated

The book's trick is a non‑portable hack that relies on taking addresses from a null pointer and doing pointer arithmetic; old Borland/Turbo compilers tolerated that, but modern toolchains (the Dev‑C++ bundles use MinGW/GCC) enforce stricter behavior and provide the standard, portable alternative: use offsetof(). (en.wikipedia.org)

Why (char ) vs (int ) gives different results: pointer arithmetic works in units of the pointed‑to type. Subtracting two char * values yields a byte difference; subtracting two int * values yields a difference in sizeof(int) units. To get a byte offset always use a char/unsigned char cast (or offsetof which already gives bytes). (gnu.org)

Two other practical points fill gaps left by the thread. First, expressions that take the address of something produced by ((type*)0)->member are fragile: the standard lets the implementation supply offsetof() correctly, but writing your own null‑pointer/address trick can be undefined or rejected by modern compilers. Use the standard macro in <stddef.h>. Second, manipulating memory by casting between unrelated struct pointer types and then writing through the result can violate alignment and the strict‑aliasing rules; that makes the code unreliable across compilers and optimization levels. (cppreference.net)

A compact, maintainable pattern is the container_of idiom: compute the container base as (char*)member_ptr minus the offsetof(type, member), then cast to the container type. For convenience:

#define container_of(ptr,type,member) ((type *)((char *)(ptr) - offsetof(type,member)))

Use size_t/ptrdiff_t for offsets, compile as C (save as .c and use a C compiler mode), and prefer offsetof/container_of or redesign over pointer hacks. 's suggestion to use offsetof() is the right, portable approach; was also correct to ask for the structures so the offset can be reasoned about. (cppreference.net)

Recommended Answers

All 4 Replies

Please post the structures.

Please post the structures.

I find this piece of code in a C book and i am unable to get the offset part of this code:

#include<stdio.h>
#include<conio.h>
void fun(struct c *p);
struct a
{
	   struct b
	   {
			  int i;
			  float f;
			  char ch;
				 }x;
				 struct c
				 {
						 int j;
			  float f;
			  char ch;
						  }y;
		}z;
		int main()
		{
		   clrscr();
		 fun(&z.y);
		 printf("\n%d %f %c",z.x.i,z.x.f,z.x.ch);
		 getch();
			return(0);
			 }
void fun(struct c *q)
{
 		   int offset;
 		   struct b *address;
 		   offset=(char *)&((struct c *)(&((struct a *)0)->y)->j)-(char *)((struct a *)0);
 		   address=(struct b *)((char*)&(q->j)-offset);
 		   address->i=1;
 		   address->f=2.1;
		   address->ch='z';
		 
			}

Please help!! Here i want to know that in offset part (char *)is used but when i used (int *)instead of (char *) result differs. Why??? and if you give explanation for

offset=(char *)&((struct c *)(&((struct a *)0)->y)->j)-(char *)((struct a *)0);

It will be a great help.

As you can see that this code is accessible in turbo C but not in Dev C++

That's because Dev-C++ is properly disallowing a language constraint violation. The address-of operator may only be used on an lvalue. You can use offsetof() to avoid the very hackish calculations that your awful book is encouraging:

#include <stdio.h>
#include <stddef.h>

struct a {
    struct b {
        int i;
        float f;
        char ch;
    } x;
    struct c {
        int j;
        float f;
        char ch;
    } y;
} z;

void fun(struct c *p)
{
    /* Find the offset of the struct c member */
    size_t offset = offsetof(struct a, y);
    
    /* 
        Find the base address of the struct b member 
        since we know it precedes the struct c member
    */
    struct b *address = (struct b*)((char*)p - offset);
    
    /* Hope and pray that what we "know" about struct a is correct */
    address->i = 400;
    address->f = 3.14;
    address->ch = 'c';
}

int main(void)
{
    fun(&z.y);
    printf("\n%d %f %c", z.x.i, z.x.f, z.x.ch);

    return 0;
}

It's still silly and unsafe, but at least the code should build and run on a modern compiler.

commented: Learned something new today :) +17

Hello everyone!!
I am new to Linux forum and have a question related to typecasting in C related to offset of structures. <snip>

Typecasting is something that happens to actors...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.