I am trying to access structure element via constant pointer. Program works like it should but I got warning 'intialization from incompatible pointer type' and '(near initalization for 'B.settings)'. I don't really know how to correctly initalize it. Can someone pls help me figure that out?
Here's my code :
It's just a snippet of larger part. Idea is to have access to structure variables x,y when moving via pointers to const structure. Hope that make sense.
#include <stdio.h>
#define PGM_STR(X) ((const char[]) { X })
struct SettingsStruct
{
unsigned int x;
unsigned int y;
}Settings;
struct constitem
{
const char * const text;
const struct constitem *next;
const struct SettingsStruct * settings;
};
struct constitem const A;
struct constitem const B = {PGM_STR("x"), &A, &Settings.x };
struct constitem const A = {PGM_STR("y"), &B, &Settings.y };
static const struct constitem *currMenuPtr=&A;
void main()
{
Settings.x = 1;
Settings.y = 2;
printf("%s\n",currMenuPtr->text);
printf("%d\n",*(currMenuPtr->settings));
currMenuPtr = currMenuPtr->next;
printf("%s\n",currMenuPtr->text);
printf("%d\n",*(currMenuPtr->settings));
}
In your code, Settings.x is an unsigned int, and therefore &Settings.x is an unsigned int *. You are trying to use it to initialize a value of type const struct SettingsStruct *. The compiler is quite right to complain -- what you are doing is highly questionable, and I suppose probably not what you actually mean to do. The same applies to Settings.y.
It looks like you could get the compiler to stop complaining (about that) by changing the type of the third element of struct constitem to unsigned int *. You'll have to judge whether that actually works for you in the larger scheme of your program, though.
There is also a problem with using &A in the initializer for variable B when A is not yet declared at the point where the initializer appears. Inasmuch as you also refer to B in A's initializer, you can't solve that by swapping the declaration order. If you really do want a circular chain of pointers, then the pointer values cannot be const, because at least one of them will need to be modified after initialization.
Related
When I declare structure given below, it is throwing compilation error.
typedef struct{
const char x; //it is throwing compilation error
const char y;
}A;
void main()
{
A *a1;
a1 = (A*)malloc(2);
}
How can I make structure's field (characters x and y) as constant?
That should be fine, but of course you can't assign to them, only use initialization.
So it doesn't make a lot of sense to allocate an instance on the heap.
This works:
#include <stdio.h>
int main(void) {
typedef struct {
const int x, y;
} A;
A my_a = { 12, 13 };
printf("x=%d\ny=%d\n", my_a.x, my_a.y);
return 0;
}
It prints:
x=12
y=13
Also, please don't cast the return value of malloc() in C.
First, you should use malloc to allocate the size of the struct, not a magic number 2. Also, don't cast malloc return value, it is automatically promoted to the compatible pointer type.
a1 = malloc(sizeof(A));
Second, there isn't really not much use to make struct member const.
A *a1;
a1 = malloc(sizeof(A));
a1's members are not initialized to any state here, yet the compiler forbidden any assignments to them, since it is defined as const, so a1->x = 'a'; won't compile.
A a2;
a2->x = 'a'; // won't compile too
The only valid use case is:
A a3 = {'a', 'b'};
You can't.
With POO in C you can disable the modification of those fields, if you:
define getters: char A_get_x(A *p); and char A_get_y(A *p);
define the struct in the .c to hide its implementation
only write typedef struct A A; in the .h file, to allow to use that type.
define a constructor : A *A_new(); which returns A with the values desired on x and y.
By doing this, you can only modify the values in the constructor, and after the object is created the values wont change (if you dont force the values with pointers etc..)
I came across this code.
typedef __mpz_struct MP_INT;
typedef __mpz_struct mpz_t[1];
Here the struct __mpz_struct is a struct that is typedefed to an array of single element. I understand that this is a trick to pass by reference in C. Then mpz_t has been used as a type to declare variables and pass them to function as parameters. Also, There was one more comment
/*
MP_INT*, MP_RAT* and MP_FLOAT* are used because they don't have side-effects
of single-element arrays mp*_t
*/
What kind of side effects are they talking about?
Passing an array to a function let's the array decay to a pointer to it's 1st element.
One can achieve the same effect by applying the Address-Of operator & to a simple variable of the same type as the array's elements.
Examples:
struct S
{
int i;
float f;
};
This
void set_S(struct S * ps)
{
ps->i = 40;
ps->f = 2.;
}
is equivalent to
void set_S(struct S ps[1])
{
ps->i = 40;
ps->f = 2.;
}
is equivalent to
void set_S(struct S * ps)
{
ps[0].i = 40;
ps[0].f = 2.;
}
is equivalent to
void set_S(struct S ps[1])
{
ps[0].i = 40;
ps[0].f = 2.;
}
One-Element-Array approach:
typedef struct S Array_of_S_with_size_1[1];
int main(void)
{
Array_of_S_with_size_1 array_of_S_with_size_1;
array_of_S_with_size_1[0].i = 0;
array_of_S_with_size_1[0].f = 0.;
set_S(array_of_S_with_size_1);
...
}
The above main() provides the same functionality as the following:
int main(void)
{
struct S s;
s.i = 0;
s.f = 0.;
set_S(&s);
...
}
I do not see any gain using the "One-Element-Array" approach. An expection might be if the &-key is broken on ones keyboard ... ;-)
I see two parts to your question. The first part, how the typedef works for passing arguments to functions, would better be illustrated with an example. Without it, I'll have to guess a bit.
In C function declarations, an array parameter is equivalent to a pointer. That's why you see (for example) equivalently for the main function,
int main(int argc, char **argv)
and
int main(int argc, char *argv[])
Similarly, if a function in your program would be declared
int func(__mpz_struct *arg)
it would be equivalent to
int func(__mpz_struct arg[])
and hence to
int func(mpz_t arg)
Also, on the calling side, if you have a variable of type mpz_t, hence the array, and you pass it to a function, the "pointer decay" takes effect: in an expression, if you use (the name of) an array it "decays" into a pointer to its first element.
This way you can call the function:
mpz_t value;
func(value);
Of course, to modify these mpz_t objects outside of the API functions, you still have to be aware of their true nature.
The side effects that you mention, I would also have to guess about them. Possibly it is meant that you have to be aware you're working with pointers inside the functions. It might be considered better to make that explicit by using the pointer syntax.
You can assign an MP_INT to another but you can not assign an mpz_t to another since assignment is not defined for arrays. If you do not want your clients to assign variables other than by your methods (which might do memory managements and stuff) this is the trick for you.
Look at this sample code
typedef char type24[3];
Same as your, but well known data type 'char' insted of your struct __mpz_struct type.
above type def means, I am using above typedef to represent char[3].
So in your sample code,
typedef __mpz_struct mpz_t[1];
mpz_t should be __mpz_struct type.
So I have one struct and I initialized a variable A with that struct data type then Ι put in some values. But now Ι need to take those values and put it into another variable B with the same struct data type. How can Ι achieve this?
struct s_Especialidade{
int id;
char nome[60];
char descricao[60];
struct s_Especialidade *proximo;
};
typedef struct s_Especialidade Especialidade;
PESPECIALIDADE p, *array;
p->nome = &array[i]->nome; //THIS LINE GIVES THE ERROR
Since it is an array of characters, you need to copy each element of the array.
strcpy(p->nome, array[i]->nome) will do it, but for extra security look at strncpy where you can set a maximum length to avoid overruns.
Try that way :
memcpy( p->nome, array[i].nome, 60 * sizeof(char) );
Or generalizing the type as well, picking the type used in the p->nome array :
memcpy( p->nome, array[i].nome, 60 * sizeof(*(p->nome)) );
This is the generalized and secure way to copy an array into another (not only for strings).
To extend the answer recommending strcpy() I'd use memcpy() and use a #defined length to make sure you always use the same value.
#define NOME_LENGTH 60
struct s_Especialidade{
int id;
char nome[NOME_LENGTH];
char descricao[60];
struct s_Especialidade *proximo;
};
typedef struct s_Especialidade Especialidade;
PESPECIALIDADE p, *array;
memcpy(p->nome, array[i]->nome, NOME_LENGTH);
Things get even more complicated trying to consider what an assignment does, but, in an example program:
struct stuff {
char buf[2];
};
int main() {
struct stuff a;
memcpy(a.buf, "aa", 2); // *Edit: "aa" is a bad example as it
// actually becomes at compilation 3 bytes long
// {'a','a','\0'} as noted in the comments
struct stuff b;
b.buf = a.buf; // *Edit: For illustrative purposes, an assignment
// between two char[2] members is not correct and
// does not compile.
}
Compilation yeilds the error error: incompatible types when assigning to type ‘char[2]’ from type ‘char *’ for the b.buf = a.buf line.
The topic of pointers and arrays has been covered elsewhere, Is an array name a pointer? among others.
*Edit: As noted in the comments, in the above code if instead of b.buf = a.buf; the struct assignemnt b = a; were done, the internal members would be copied correctly. This is because struct to struct assignment is effectively memcpy(&b, &a, sizeof(b)); (Assign one struct to another in C)
Can someone tell me the difference between these two versions of a declaration of a structure?
struct S
{
uint8_t a;
};
and
const struct S
{
uint8_t a;
}
Followed by:
void main(void)
{
struct S s = {1};
s.a++;
}
Hint, i've tried both versions for S in Visual Studio C++ 2010 Express so I know that both compile with errors.
Is the "const struct" doing nothing at all? "const struct S s = {1};" certainly does, but that's not the issue at the moment.
Regards
Rich
/********************************************/
I've just worked out what
const struct <typename> <{type}> <variable instances a, b, .., z>;
is doing:
When const is present before the "struct", all variable instances are const, as though they'd be defined with:
const struct <typename> a, b, z;
So it does do something, but not when there's no instance definitions in-line with the struct declaration.
Rich
A declaration of structure just defines the data type.
const qualifier appies to a variable not a data type. So adding const preceeding a struct declaration should be redundant at the most.
With:
const struct S
{
uint8_t a;
};
The const qualifier there is nonsense, and may even cause a compilation error with some C compilers. gcc issues a warning.
The intent appears to be to declare the data type struct S. In this case, the proper syntax is:
struct S
{
uint8_t a;
};
const struct S
{
uint8_t a;
};
is not a valid construct.
This
const struct S
{
uint8_t a;
} x;
could possibly be valid as you're declaring a variable x that is now const, meaning it cannot change.
The const qualifier applies to variables or members.
To instantiate a const variable, just specify const during instantiation.
What const does, is:
during compilation, verify that only reads are performed on the const variables
if the const variable is created with a value which can be resolved during compilation, put the variable in the program memory
When const is applied to members, like in:
struct T {
int const i;
int j;
};
You can only (legally) assign the value i during the creation of the structure.
You may be able to modify a const value (if the program memory sits in RAM and not ROM) by casting it to a non-const type (const-cast) but this is something you shouldn't do.
The typical usage of const-cast is when you use a library which does not specify the constness in function declarations, and your code does. At this point if you want to use it you have to trust it and cast parameters before calling its functions.
It is nonsense to use const keyword before struct.
If you are using gcc compiler, it shows you the following warning:
warning: useless type qualifier in empty declaration [enabled by default]
This is the only use I can think of:
const struct S {
int a;
int b;
} s;
This declares a struct and immediately creates an instance for it named s and at this point, a and b in s are initialized to 0 (please note that at this point s is a global variable in the translation unit which it has been declared in and can be externally linked to).
printf("a = %d\t b = %d\n", s.a, s.b); // a = 0 b = 0
If you try to set members of s, you will fail:
s.a = 1; //error: assignment of member ‘a’ in read-only object
So, s is not really useful here...unless you do something like:
const struct S {
int a;
int b;
} s = { 1, 2 };
Now let's create another instance of the same struct (declaration is still same as above):
struct S other;
other.a = 1;
other.b = 2;
printf("a = %d\t b = %d\n", other.a, other.b); // a = 1 b = 2
The compiler will not complain anymore as other is not const! only s is const!
Now, what that const do, you may ask? let's try to change s:
s = other; // error: assignment of read-only variable ‘s’
That is all to it. If you did not need the compiler to allocate storage for s at the point of declaration and still needed an instance of s to be const you would just add const at the point of instantiating struct S (note the capital S!!)
Bonus 1
const struct S {
int a;
int b;
};
note that there is no small s anymore. At this point, GCC will warn you that const qualifier does not do anything!!!!
Bonus 2
If you want every instance of the struct to be const, that is its members can only be initialized at the point of definition you can do like (using typedef):
typedef const struct S {
int a;
int b;
} s;
// The wrong way
s thisIsAnS;
thisIsAnS.a = 1; //error: assignment of member ‘a’ in read-only object
// The correct way
s thisIsAnS = { 1 , 2 }; //compiles fine, but you can not change a or b anymore
Conclusion
To me, this is just syntactic sugar and only adds unnecessary complexity to the code. But who am I to judge...
When you declare
const var;
then it allocate the some memory space for it but
struct var;
it was just an declaration compiler does not allocate any space for it.
so it shows the error and in const struct you didn't declare any varible see the code so it shows error.
What is the use of typedef keyword in C ?
When is it needed?
typedef is for defining something as a type. For instance:
typedef struct {
int a;
int b;
} THINGY;
...defines THINGY as the given struct. That way, you can use it like this:
THINGY t;
...rather than:
struct _THINGY_STRUCT {
int a;
int b;
};
struct _THINGY_STRUCT t;
...which is a bit more verbose. typedefs can make some things dramatically clearer, specially pointers to functions.
From wikipedia:
typedef is a keyword in the C and C++ programming languages. The purpose of typedef is to assign alternative names to existing types, most often those whose standard declaration is cumbersome, potentially confusing, or likely to vary from one implementation to another.
And:
K&R states that there are two reasons for using a typedef. First, it provides a means to make a program more portable. Instead of having to change a type everywhere it appears throughout the program's source files, only a single typedef statement needs to be changed. Second, a typedef can make a complex declaration easier to understand.
And an argument against:
He (Greg K.H.) argues that this practice not only unnecessarily obfuscates code, it can also cause programmers to accidentally misuse large structures thinking them to be simple types.
Typedef is used to create aliases to existing types. It's a bit of a misnomer: typedef does not define new types as the new types are interchangeable with the underlying type. Typedefs are often used for clarity and portability in interface definitions when the underlying type is subject to change or is not of importance.
For example:
// Possibly useful in POSIX:
typedef int filedescriptor_t;
// Define a struct foo and then give it a typedef...
struct foo { int i; };
typedef struct foo foo_t;
// ...or just define everything in one go.
typedef struct bar { int i; } bar_t;
// Typedef is very, very useful with function pointers:
typedef int (*CompareFunction)(char const *, char const *);
CompareFunction c = strcmp;
Typedef can also be used to give names to unnamed types. In such cases, the typedef will be the only name for said type:
typedef struct { int i; } data_t;
typedef enum { YES, NO, FILE_NOT_FOUND } return_code_t;
Naming conventions differ. Usually it's recommended to use a trailing_underscore_and_t or CamelCase.
Explaining the use of typedef in the following example. Further, Typedef is used to make the code more readable.
#include <stdio.h>
#include <math.h>
/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/
// typedef a primitive data type
typedef double distance;
// typedef struct
typedef struct{
int x;
int y;
} point;
//typedef an array
typedef point points[100];
points ps = {0}; // ps is an array of 100 point
// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)
// prototype a function
distance findDistance(point, point);
int main(int argc, char const *argv[])
{
// delcare a function pointer
distanceFun_p func_p;
// initialize the function pointer with a function address
func_p = findDistance;
// initialize two point variables
point p1 = {0,0} , p2 = {1,1};
// call the function through the pointer
distance d = func_p(p1,p2);
printf("the distance is %f\n", d );
return 0;
}
distance findDistance(point p1, point p2)
{
distance xdiff = p1.x - p2.x;
distance ydiff = p1.y - p2.y;
return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
} In front of everything, place the keyword typedef.
*/
typedef doesnot introduce a new type but it just provide a new name for a type.
TYPEDEF CAN BE USED FOR:
Types that combine arrays,structs,pointers or functions.
To facilitate the portability , typedef the type you require .Then when you port the code to different platforms,select the right type by making changes only in the typedef.
A typedef can provide a simple name for a complicated type cast.
typedef can also be used to give names to unnamed types. In such cases, the typedef will be the only name for said type.
NOTE:-SHOULDNT USE TYPEDEF WITH STRUCTS. ALWAYS USE A TAG IN A STRUCTURE DEFINITION EVEN IF ITS NOT NEEDED.
from Wikipedia:
"K&R states that there are two reasons for using a typedef. First ... . Second, a typedef can make a complex declaration easier to understand."
Here is an example of the second reason for using typedef, simplifying complex types (the complex type is taken from K&R "The C programming language second edition p. 136).
char (*(*x())[])()
x is a function returning pointer to array[] of pointer to function returning char.
We can make the above declaration understandable using typedefs. Please see the example below.
typedef char (*pfType)(); // pf is the type of pointer to function returning
// char
typedef pfType pArrType[2]; // pArr is the type of array of pointers to
// functions returning char
char charf()
{ return('b');
}
pArrType pArr={charf,charf};
pfType *FinalF() // f is a function returning pointer to array of
// pointer to function returning char
{
return(pArr);
}
It can alias another type.
typedef unsigned int uint; /* uint is now an alias for "unsigned int" */
typedef unsigned char BYTE;
After this type definition, the identifier BYTE can be used as an abbreviation for the type unsigned char, for example..
BYTE b1, b2;