4

I have the following types, for illustration:

struct outer {
  struct inner {
    const int c;
    int x;
  } i;
  int y;
};

I want to malloc outer and then, later, initialize inner to get the right const behavior for outer.i.c.

For example, something like

struct outer *o = malloc(sizeof *o);
o->y = find_y();
int cc = find_c();
int xx = find_x();
o->i = { .c = cc, .x = xx };

but this gives me an error about assignment of read-only member 'i', because it's an assignment, not an initialization.

Is there a way to do something like this that's up-front to the compiler? Let's consider tricks like casting away const with *((int *) &o->i.c) or using memcpy on &o.i as sneaking around the compiler. I can get the bits where they need to be, but I am looking for the least sneaky way to do this.

I am not using C++ (I'm using C99).

2
  • Technically, it is not an initialisation, but just an assignment. the initial struct outer *o = malloc(sizeof *o); is an initialisation, but that is only the pointer being initialised, not where it points at. So you need to explicitly assign o->i.c and o->i.x, or assign both of them in one sweep via a struct assignment (which can be using a "struct literal", since c99) . Commented May 17, 2012 at 14:16
  • edited to hopefully clear things up. Commented May 17, 2012 at 14:20

2 Answers 2

1

The only really constant things are things residing in read-only memory. Malloc/calloc will never give you read-only memory. So that "const" there is a lie. Well, it is a hint for compiler(s) and to developer(s). I am not sure if there are any syntax sugars in C99 to address something that might seem an issue to someone, but here is how I would do it:

#include <stdio.h>
#include <stdlib.h>

struct outer {
    struct inner {
        const int c;
        int x;
    } i;
    int y;
};

int main(void)
{
    struct outer    *o;

    o      = calloc(1, sizeof(struct outer));

    printf("before: %d %d %d\n", o->i.c, o->i.x, o->y);

    *((int *)&o->i.c) = 1;
    o->i.x = 2;
    o->y = 3;

    printf("after: %d %d %d\n", o->i.c, o->i.x, o->y);

    return 0;
}

Please take into account that this is a more practical solution than academic, thus some people might want to throw a few rotten eggs at me for it.

Sign up to request clarification or add additional context in comments.

4 Comments

I am aware of this. I'm looking for the least sneaky approach (where memcpy and casting away const are sneaky).
leif: Well, if you were initializing, you could place it on stack, or in data segment, then you could use struct outer o = { { 1, 2 }, 3 };, but malloc returns you memory (that is BTW is already initialized by mmap for example, to 0, or could have been used elsewhere and contain "garbage") and so you have to write to that memory to do things, and that implies casting const away.. Whether there is a special syntax for it or no IDK, but even if there was I'd not use it - why bother?
@leif: you're using const for member-level access control of allocated objects; C++ provides such access control mechanisms, but C does not - there just isn't a non-sneaky way to do what you want...
In C++ it is called a placement-new.
0

I would probably do this:

struct outer_init {
  struct inner_init {
    int c;
    int x;
  } i;
  int y;
};

struct outer_init *oi = malloc(sizeof *oi);
oi->y = find_y();
oi->i.c = find_c();
oi->i.x = find_x();

struct outer *o = (struct outer *)oi;

I am not completely sure that it is absolutely portable though.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.