-3

I want to use a single pointer pt and a offset size_t offp to update the value of either myNFO.valueA or myNFO.valueB depends on run time conditions.

I can set pt to &myNFO, but I do not know the proper type of pt and how should I calculate offp.

Edited:

  • I forget to mention the structures I used are allocated at runtime.

  • I am using khash, which need to distinguish whether a key exists. If I use pt = &pNFO->valueA;, I have to write similar codes twice. Thus I want to determine which member first and then turn to the hash.


typedef struct {
    uint16_t valueA;
    uint16_t valueB;
    const char * fileName;
} __attribute__ ((__packed__)) Info_t;

Info_t myNFO, *pNFO;

pNFO = calloc(1,sizeof(Info_t));

size_t offp = &(myNFO.valueB) - &(myNFO.valueA);

if (ret==1) {
    pt = pNFO;
} else {
    pt = pNFO + offp;
}

*pt = 100;
Galaxy
  • 1,862
  • 1
  • 17
  • 25
  • 1
    The compiler does this for you when you write `myNFO.valueB`. If you want to access an element through a pointer, you can use `pNFO->valueB`. The compiler does the same offset calculation. – Tim Jun 10 '16 at 22:25
  • Why not just `uint16_t *pt = ret == 1 ? &pNFO->valueA : &pNFO->valueB;`? – melpomene Jun 10 '16 at 22:43
  • Why aren't you using `offsetof()`? – Barmar Jun 10 '16 at 22:50

4 Answers4

1

Use offsetof()

size_t offp;
if (some condition) {
    offp = offsetof(Info_t, valueA);
} else {
    offp = offsetof(Info_t, valueB);
}
*(uint16_t*)((char*)pNFO + offp) = 100;

You need to do all the pointer casting because offsetof() returns the offset in bytes. So first you have to cast the struct pointer to char* to add the bytes to it, then cast that to a pointer to the element type to assign to it.

Barmar
  • 741,623
  • 53
  • 500
  • 612
0

You can simply do:

if (ret==1) {
    pt = &pNFO->valueA;
} else {
    pt = &pNFO->valueB;
}

If the intention is to have many more members consider doing:

typedef struct {
    uint16_t value[MAX_VALUES];
    const char * fileName;
} __attribute__ ((__packed__)) Info_t;


if (ret < MAX_VALUES) {
    pt = &pNFO->values[ret];
}

since pt is pointing to a uint16_t, it should be a uint16_t pointer:

uint16_t *pt;
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • I am using `Info_t` as value of a hash table. If I set `pNFO` first, I need to write 2 similar codes for whether its key exists. – Galaxy Jun 10 '16 at 23:05
0

I'm going to say first that you are probably doing this the wrong way. But to let you shoot yourself in the foot:

uint16_t* pt;
if (ret==1) {
    pt = (uint16_t*)pNFO;
} else {
    pt = (uint16_t*)pNFO + offp;
}
*pt = 100;

A better way would be:

uint16_t* pt;
if (ret==1) {
    pt = &pNFO->valueA;
} else {
    pt = &pNFO->valueB;
}
*pt = 100;
Mark Lakata
  • 19,989
  • 5
  • 106
  • 123
  • I am using [khash](https://github.com/attractivechaos/klib/blob/master/khash.h) of the struct, thus it is allocated at runtime. – Galaxy Jun 10 '16 at 22:45
  • 2
    @Galaxy Why does it matter that it's allocated at runtime? – melpomene Jun 10 '16 at 22:50
  • structs are a compile time object. Do you mean that the memory for the struct is allocated at runtime? Doesn't make any difference. – Mark Lakata Jun 10 '16 at 22:50
0

It works now. But I think setting offset this way seems like Magic Numbers, and I want to avoid this if there are some better way.

typedef struct {
    uint16_t insertSize;
    uint16_t SD;
    const char * fileName;
} __attribute__ ((__packed__)) BamInfo_t;

KHASH_INIT(bamNFO, kh_cstr_t, BamInfo_t, 1, kh_str_hash_func, kh_str_hash_equal)
bamNFOp = kh_init(bamNFO);

BamInfo_t tbam, *pbam;

while(READFILE) {
    ... ...
    char * id = strdup(name);
    uint16_t *pt;
    size_t offset = 0;
    if (strspn(".SD",name)==3) {
        size_t idLen = strlen(name);
        id[idLen-3] = '\0';
        offset = 1;
    }
    ki = kh_put(bamNFO, bamNFOp, id, &absent);
    if (absent) {
        kh_key(bamNFOp, ki) = id;
        pt = (void*) &tbam;
        *(pt+offset) = atol(value);
        kh_value(bamNFOp, ki) = tbam;
    } else {
        free(id);
        pt = (void*) &kh_value(bamNFOp, ki);
        *(pt+offset) = atol(value);
    }
}
Galaxy
  • 1,862
  • 1
  • 17
  • 25