0

Is what am I trying to do in C possible?

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

struct foo{
    int const * const a;    // constPtrToConst is a constant (pointer)
                            // as is *constPtrToConst (value)
};

struct faa{
    int b;
};

int main(void){
    struct foo *x = (struct foo*)malloc(sizeof(struct foo));
    struct faa *y = (struct faa*)malloc(sizeof(struct faa));

    x->a = &(y->b);     // error: assignment of read-only member ‘a’ [that's ok] 
                        // (I)
    x->a++;    // It should not do this either...

    printf("%d,\t%p\n", *(x->a), x->a);    // (II)
    free(x);
    free(y);
}

How can I initialize (I) and could I get this (II)?

Sorry is not assign is initialize with that pointer.

This is what I want to get but dynamically.

#include <stdio.h>

struct foo{
    int const * const a;
};

int main(void){
    int b = 5;
    struct foo x = {
        .a = &b
    };
    printf("%d\n", *(x.a));
}

This is how I solve it.

I don't know if is the best choice.

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

struct foo{
    int const * const a;
};

struct foo* newfoo(int *var){
    struct foo *tempD = malloc(sizeof(struct foo));
    struct foo tempS ={
        .a = var
    };
    memcpy(tempD, &tempS, sizeof(struct foo));

    return tempD;
}

int main(void){
    int b = 5;

    struct foo *z = newfoo(&b);

    printf("%d,\t%p\n", *(z->a), z->a);
    // this is equivalent to printf("%d,\t%p\n", b, &b);

    free(z);
}

5 Answers5

1

int const * const a; is a type of variable which is constant means that it cannot be changed (second const), while first const means that it points to constant data.

Change your structure to:

struct foo{
    const int* a;
};

Now you can assign value to a but you cannot modify value where a points.

struct foo myFoo;
myFoo.a = (int *)5; //a points to location 5 now, valid
*myFoo.a = 4;       //Try to modify where a points = invalid and error

What is the difference between const int*, const int * const, and int const *?

unalignedmemoryaccess
  • 7,246
  • 2
  • 25
  • 40
  • `const` does not mean _constant_. A `const` object is not a constant, and the object is not immutable; it just can't be changed through assignment. – ad absurdum Jun 16 '17 at 11:41
  • @DavidBowling What is then if it is not *constant*? We are talking about *object* not about *pointer inside object*. You can change it via `memcpy`or similar but you can't directly write to it using `...a = something;` – unalignedmemoryaccess Jun 16 '17 at 11:42
  • It is what I said in my comment; you can't modify a `const` object through assignment. It is a guarantee for the compiler and for the programmer. Yet a `const` object can be modified.... – ad absurdum Jun 16 '17 at 11:44
  • I think even `memcpy` can't be used to modify a `const` object. Since it takes `void*` in the destination argument and not `const void*`. – Ajay Brahmakshatriya Jun 16 '17 at 13:58
  • @AjayBrahmakshatriya C will allow you. – unalignedmemoryaccess Jun 16 '17 at 13:59
1

You have to use memcpy in this case; you can't assign through a const expression:

int *temp = &y->b;
memcpy((void *)&x->a, &temp, sizeof temp);

In order to effect x->a++ you could do:

int *temp;
memcpy(&temp, &x->a, sizeof temp);
++temp;
memcpy((void *)&x->a, &temp, sizeof temp);
M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    I wonder if this is really well-defined behavior. And what if the system has true NVM and allocates the const pointer in flash? – Lundin Jun 16 '17 at 11:57
  • Yes it's well-defined. There are no const pointers allocated in my code, there is only space allocated by malloc (which must be writable) and it is legal to access non-const objects via a const lvalue of the matching effective type (memcpy copies the effective type). Copying from a const object into malloc'd space does not make the malloc'd space constant either. – M.M Jun 16 '17 at 12:10
  • This brings up an important question. Should const qualifier be allowed on members? Shouldn't all the members take the qualifier from the struct definition​?(I only mean the outer most type, qualifiers for pointed type should still be there). – Ajay Brahmakshatriya Jun 16 '17 at 13:52
  • @M.M. I think `&x->a` would result in `int const * const *`, which will get casted to `const void *`. I don't think it should be passed as first arg of `memcpy`. The compiler should complain. – Ajay Brahmakshatriya Jun 16 '17 at 13:55
  • @AjayBrahmakshatriya you're right about the first argument to memcpy. I never use const inside a struct for the reasons you mention, it just complicates the code for no real benefit – M.M Jun 16 '17 at 23:21
0

You can't assign to x->a after initialization, so you would have to do something silly like:

struct faa *y = (struct faa*)malloc(sizeof(struct faa));
struct foo tmp = {&y->b};
struct foo *x = (struct foo*)malloc(sizeof(struct foo));
memcpy(x, &tmp, sizeof *x); 
nos
  • 223,662
  • 58
  • 417
  • 506
0

This is the same scenario:

  • I locked the door and threw away the key since nobody including myself should ever open that door in any situation.
  • Immediately after doing that, I noticed that I cannot open the door!
  • I need to open this door! How do I do that? I threw away the key.

You have to 1) know what you are doing, and 2) don't do things that you actually don't want to do, including not making a program design specification that contradicts the actual needs of the program.

Simply change the declaration to int const* a; if you intend to change where that pointer points at.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

Why not typecasting. The following code will print 6.

int main()
{
    int x = 5;
    const int* c{ &x};
    int* p{( int*) c};
    *p = 6;
    std::cout << x << std::endl;
}

baz
  • 1,317
  • 15
  • 10