If I have created a C module that presents a handle to the user with a pointer to a forward declared struct, like so:
typedef struct FOO_Obj *FOO_Handle;
If I then declare function prototypes that use it as a const qualified parameter thusly:
void FOO_work(const FOO_Handle fooHandle);
How is the const-ness applied?
const struct FOO_Obj *FOO_Handle // A
struct FOO_Obj *const FOO_Handle // B
const struct FOO_Obj *const FOO_Handle // C
Or is it UB?
B. ( There is no undefined behavior with the code you presented. )
The function call
void FOO_work(const FOO_Handle fooHandle);
is equivalent to
void FOO_work(struct FOO_Obj* const fooHandle);
Variable fooHandle in the function will becode a const pointer to a non-const struct FOO_Obj object. You will not be able to add the const qualifier to fooHandle to make it a pointer to a const object.
Instead, if you want to have a pointer to a const object, and keep the struct hidden, you must make another typedef:
typedef const struct FOO_Obj* FOO_ConstHandle;
Related
Let's say test_t is defined as follows:
typedef struct test_t {
void *unused;
} *(test_t)
Is it possible define a variable to be a pointer to const without modifying the definition of test_t?
const test_t var would be a const pointer to struct test_t, right?
I have this problem since sonarqube recommends to "Make the type of this variable a pointer-to-const" but I can't change the definition since it is used in many other places where the variable should be a pointer to struct test_t.
Do not hide pointers behind typedefs. It is a very bad practice and in your case it makes impossible to declare such variable.
typedef struct test_t {
void *unused;
} test_t;
const test_t *var;
This typedef declaration
typedef struct test_t {
void *unused;
} *(test_t);
declares the name test_t as an alias for the type struct test_t *.
So this declaration
const test_t var;
that may be equivalently written like
test_t const var;
actually denotes the following declaration
struct test_t * const var;
That is it declares the variable var as a constant pointer not as a pointer to a constant object of the type struct test_t.
If you want to declare the variable var as a pointer to constant data then you have to write
const struct test_t *var;
If you want to declare a constant pointer to constant data then you have to write
const struct test_t * const var;
However if you want to declare a constant pointer then you need to initialize it in its declaration.
Otherwise you could rewrite the typedef declaration the following way
typedef struct test_t {
void *unused;
} test_t;
and then write
const test_t *var;
In this case the name test_t is an alias for the type specifier struct test_t and the qualifier const produces the type specifier const struct test_t.
Yes it is possible to do without modifications. You just need to copy-paste the entire typedef and then change that, e.g.
typedef const struct {
void *unused;
} *const_test_t;
Of course you couldn't pass this to anything that requires pointer to non-const test_t and such.
However if the declaration indeed uses struct test_t {...} then do note that it also declares the struct tag test_t, which you can use too. So, instead of
const test_t var:
you would use the struct tag with the struct keyword:
const struct test_t *ptr;
But if the struct was declared anonymously i.e. typedef const struct { } *test_t; then copying is the only option.
The real fix is (as everyone says here) to not use a typedef to hide pointers wherever they shouldn't be.
I am programming a module on a microcontoller for interfacing it's EEPROM to receive some user data from there. Since you can not overwrite the EEPROM easily I want to return a const pointer to const data.
Now my functions prototype looks like this:
const struct userData const* getEEPROMDataAtIndex(uint32_t uidIndex)
while gcc tells me duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]. Shouldn't each const I use have a different effect? One to make the pointed-to data immutable, the other for the received pointer not to be retarged?
You have declared your struct const twice. Since it doesn't make sense to make the pointer const in a return type, just remove one of the const declarations. If you wanted to make the pointer const (which doesn't really make sense in a return type) you would put const after the asterisk.
You seems have some miss understanding about const, for example.
#include <stdio.h>
int main()
{
int a=123, b=456;
const int *pa = &a;
pa = &b; //legal
*pa = 4; //illegal
printf("a=%d\n", a);
return 0;
}
gcc will give an error saying that
x.c: In function ‘main’:
x.c:8:9: error: assignment of read-only location ‘*pa’
*pa = 4;
^
for your purpose, if I understand correctly, you should define the function as
const struct userData * getEEPROMDataAtIndex(uint32_t uidIndex);
//this const declare the returned pointer point to something cannot be changed
then when you initiate your constant pointer by call this function
const struct userData * const myp = getEEPROMDataAtIndex(index);
// ^ this declare the pointer itself (myp) cannot be changed
Hope this helps.
const struct userData const* => const struct userData *const
It can be used during the initilalisation of the automatic variable:
const struct userData * const foo(void);
void bar(void)
{
const struct userData *const ptr_to_something = foo();
/* some code */
}
I suggest using typdef to type define your return data type. Then in the function declaration you only need to declare the return type as the typedef name.
For example...
typedef struct USER_DATA
{
....
...
};
I think it would simplify things a bit.
what happens if you interchange 'const struct' ... to 'struct const'?
I have the following struct:
struct foo
{
...
char* cp;
};
And I want to pass a struct foo type pointer to a function, but I want the function to cast the pointer to const char* const cp, and I don't want the const qualifier as part of the definition of struct foo. Declaring the function as:
void func (const struct foo* foo_i);
will ensure the pointer cp is unchanged, but not the data it points to. Is there a way to declare the function so that the data is ensured to be read-only too?
What you describe is not possible.
Consider making cp of type const char*.
I'm trying to initialize an array of structs. The struct contains a function pointer as one of its data members. But my compiler is giving me an error complaining that The initializer element is not constant. How can I initialize the array with my declared function pointer?
typedef void (*write_func_ptr_t)( void**, size_t*, char*, const size_t);
typedef bool (*read_func_ptr_t)( char*, const void*, const size_t);
write_func_ptr_t generate_basic_msg_ptr;
read_func_ptr_t handle_basic_msg_ptr;
write_func_ptr_t generate_reg_msg_ptr;
read_func_ptr_t handle_reg_msg_ptr;
struct supported_msg_info
{
const char* const type;
const write_func_ptr_t write_func;
const read_func_ptr_t read_func;
};
static struct supported_msg_info SUPP_MESSAGES[] = {
{ "basic", generate_basic_msg_ptr, handle_basic_msg_ptr },
{ "registration", generate_reg_msg_ptr, handle_reg_msg_ptr }
};
You can do that, add the functions declarations and make them match the function pointer types like this
void generate_basic_msg_ptr(void **, size_t *, char *, const size_t);
bool handle_basic_msg_ptr(char *, const void *, const size_t);
void generate_reg_msg_ptr(void **, size_t *, char *, const size_t);
bool handle_reg_msg_ptr(char *, const void *, const size_t);
But according to your comment
The definitions of the functions are going to be pulled in at runtime from a shared library using dlsym – agranum 59 secs ago
What you really need is this
struct supported_msg_info
{
const char *const type;
/* remove the const qualifier */
write_func_ptr_t write_func;
read_func_ptr_t read_func;
};
static struct supported_msg_info SUPP_MESSAGES[] = {
{"basic", NULL, NULL},
{"registration", NULL, NULL}
};
and then when you call dlsym you can do this
SUPP_MESSAGES[0].write_func = dlsym(dlhandle, "symbol_name");
the function poitner SUPP_MESSAGES[0].write_func will then be called with the signature specified by your struct definition and function pointers typedef's and remember that void * is convertible to any type of pointer without casting, so this is all you need.
generate_basic_msg_ptr and friends are just variables that are not even initialized(well, strictly speaking they might have been initialized to zeros, but it is probably not your intention). So they have no compile-time defined values, and obviously cannot be used for array initialization. You might want to declare a functions like void func(<whatever>);, and use func in the initialization.
This question already has answers here:
typedef pointer const weirdness
(6 answers)
Closed 8 years ago.
I have a struct type_s. Then I typedef a pointer to a struct type_s as type.
If I have a const struct type_s* then the compiler will correctly complain if an assignment is made to the struct member, as seen in function Test1(). But if I make a const type, which is a typedef for the same struct pointer the compiler will not complain and compile, function Test2().
typedef struct type_s* type ;
struct type_s
{
int a ;
} ;
void Test1( const struct type_s* t )
{
t->a = 123 ; //complains, ok
}
void Test2( const type t )
{
t->a = 123 ; //doesn't, it should in my oppinion
}
To me they are logically both the same thing. What am I missing?
Is the only solution to create another typedef for a constant pointer to that struct like this:
typedef const struct type_s* ctype ;
which will work correctly as in Test1().
What you're missing is that a const pointer is not the same thing as a pointer to a const object. You have one of each. A const pointer is a pointer whose stored address is not modifiable; a pointer to const is one which cannot be used to modify its referent.
They are not the same thing. const has different semantics when applied to the definition or declaration of a pointer variable and a non-pointer variable.
const struct type_s *t
The above statement defines t to be a pointer to an object of type const struct type_s. Here, const qualifies the type struct type_s of the object t points to, not the pointer t.
typedef struct type_s *type ;
The above statement defines an alias named type for the type struct type_s *.
const type t;
// equivalent to
type const t;
// equivalent to
struct type_s *const t;
The above statement defines t to be a constant object of type type. Here const qualifies the object. You cannot replace the typedef with its original type and reinterpret it as if it were a macro. The pointer information is embedded in the typedef and it will be treated as a non-pointer type.