4

One solution to print the offset of the checksum field in the info struct, is to use the macros typeof and offsetof:

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

typedef struct
{
    struct {
       int a;
    } something;

    struct {
        int a;
        int b;
        int c[42];
        uint32_t checksum;
        int padding[10];
    } info[2];
    // ...
} S;

int main(void)
{   
    S s;
    printf("%lu\n", offsetof(typeof(s.info[0]), checksum));
    return 0;
}

Unfortunately, typeof is not standard, so I am looking for a more convenient way to write the above example without having to declare info outside from S.

Why I am trying to do this?

I have a big structure that represent the content of a FLASH memory that represent blocks of information. Each of these blocks have a checksum that I would like to check:

if (s.info[0].checksum != checksum(s.info[0], offsetof(typeof(s.info[0]), checksum))) {
    printf("Oops\n");
}

The writing is not portable because of typeof.

nowox
  • 25,978
  • 39
  • 143
  • 293

2 Answers2

3

I don't know why you are thinking a (non-existing in Standard C) typeof is required. This goes swimmingly with offsetof if you give the struct a tag (information):

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

typedef struct
{
    struct {
        int a;
    } something;

    struct information {
        int a;
        int b;
        int c[42];
        uint32_t checksum;
        int padding[10];
    } info[2];
    // ...
} S;

int main(void)
{
    printf("%zu\n", offsetof(S, info[0].checksum));
    printf("%zu\n", offsetof(S, info[1].checksum));
    printf("%zu\n", offsetof(struct information, checksum));
    printf("%zu\n", offsetof(S, info[0].checksum) - offsetof(S, info[0].a));
    return 0;
}

Example run:

$ ./a.out
180
400
176
176

BTW, don't bother with typedefs for structs. They are useless. You don't have to believe me, but you can believe Peter van der Linden.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 3
    Why do we have to believe Peter van der Linden? It's just personal style. I like using typedefs because then if I make a typo, it tells me about undeclared identifier, instead of getting a cryptic incompatible-type error at some different part of the code – M.M Mar 17 '17 at 09:39
  • That's very interesting. So the scope of `struct information` is global. I didn't know that and it means I cannot declare another struct `information` somewhere. So naming the struct in this particular case is a very bad idea because I can have a conflict. – nowox Mar 17 '17 at 09:59
  • @nowox The beginning of s and s.info[0] are guaranteed to be the same (offset 0) by the C Standard since they are the first member. – Jens Mar 17 '17 at 10:01
  • @Jens Yes for `s.info[0]`, but not for `s.info[1]` – nowox Mar 17 '17 at 10:01
  • @Jens I can believe Peter van der Linden and I just bought it's book :) – nowox Mar 17 '17 at 10:07
  • @nowox You can do without the tag name if you do the arithmetic yourself: `printf("%zu\n", offsetof(S, info[0].checksum) - offsetof(S, info[0].a));` But like I said, the second term is guaranteed to be 0 in your case where the info[] array is the first member. – Jens Mar 17 '17 at 10:07
  • @nowox When info[] is not the first member, the third and fourth printf will give the same correct offset of just the checksum member from the beginning of the substruct (information). I have updated my answer. – Jens Mar 17 '17 at 10:21
0

Use pointer arithmetic. Get the address of the element, and then subtract that from the address of the structure.

((unsigned char *) &(s.info[0]).checksum - (unsigned char *) &(s.info[0]))
Mayazcherquoi
  • 474
  • 1
  • 4
  • 12
  • It works and it is portable, but I feel it's less readable than my initial suggestion – nowox Mar 17 '17 at 09:25
  • @nowox It is perfectly fine. Every proficient C programmer will know what you want. if you're that worried, document that little tidbit of code (// Get the offset of the element checksum in structure.), or stick it in a function. – Mayazcherquoi Mar 17 '17 at 09:27
  • 1
    note that the result of the subtraction has type `ptrdiff_t`, which uses format specifier `%jd` if you want to printf it – M.M Mar 17 '17 at 09:38
  • 1
    Two casts is ugly as hell. `offsetof` can do this just fine. – Jens Mar 17 '17 at 09:46
  • @Jens Subjective. I think two casts in this instance is fine. I agree, `offsetof` would be the better choice, but I interpreted the OP to mean that they did not want to use any macros or non-standard behaviour, so I answered as such. – Mayazcherquoi Mar 17 '17 at 09:59
  • @Mayazcherquoi Fair enough. If offsetoff is unavailable (K&R C) I would use the casts. – Jens Mar 17 '17 at 10:24