We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello!
Iam currently working on a project with the XC2785X-104F Controller, uVision 4 and Keil C166 Compiler. Within my code i have to work with matrices and several matrix calculations. Therefor iam working with double pointers, structs and 2 dimensional arrays.
######################### Code snippet ###################
#################################### matrix struct (incl col,row)
typedef struct { int row; int col; } MATHEAD;
typedef struct { MATHEAD head; double *matrix; } MATBODY;
typedef double **MATRIX;
#define Mathead(a) ((MATHEAD *)((MATHEAD *)(a) - 1)) #define MatRow(a) (Mathead(a)->row) #define MatCol(a) (Mathead(a)->col)
############################################# struct to work with
typedef struct { MATRIX A, B, C; double var;
}structure;
############################################ func to "create" matrices
MATRIX mat_creat( row, col, type ) int row, col, type; { MATRIX A;
if ((A =_mat_creat( row, col )) != NULL) { return (mat_fill(A, type)); } else return (NULL);
return (A); }
MATRIX _mat_creat( row, col ) int row, col; { MATBODY *mat; int i;
if ((mat = (MATBODY *)malloc( sizeof(MATHEAD) + sizeof(double *) * row)) == NULL) return NULL;//(mat_error( MAT_MALLOC ));
for (i=0; i<row; i++) { if ((*((double **)(&mat->matrix) + i) = (double *)malloc(sizeof(double) * col)) == NULL) return NULL;//(mat_error( MAT_MALLOC )); }
mat->head.row = row; mat->head.col = col;
return (&(mat->matrix)); //(& ) }
########################### main.c
structure test1;
// value for var test1.var = 1.234;
// send data via uart to terminal send_uart(test1.var); // works fine
// create a 2x1 matrix with unknown data test1.A = mat_creat(2,1,UNDEFINED);
// fill matrix with values test1.A[0][0] = 0x00; // <--------- causes uC-freeze at this point
// send data via uart to terminal send_uart(test1.A[0][0]); // is not delivered send_uart("TEST\n"); // is not delivered
########################## END Code snippet ##############################
If i comment that line out (// test1.A[0][0] = 0x00;) everything works fine. If not, there is no error nor a warning from the compiler. Just a freeze on the uC.
In my eyes the error lies in the usage of the double pointer, but i can't find the mistake. Also tried the same code in eclipse with gnu c compiler and everything worked fine...
Does anybody know where the problem is? Did anyone make similar experiences??
I hope someone can help me!
thank you!
Bye, Josh
My car had a problem recently so I took it to the garage. The problem was caused by a nut not being correctly tightened. Why wasn't it correctly tightened? Simple, it was the wrong type.
Probably best to ban all nuts.
Oh my, dude, are you in way over your head.
First you thought you were qualified to insult other people's contributions without so much a hint of an argument of your own. I was going to let that pass as the usual childish nonsense of an anonymous coward.
But that apparently wasn't enough for you. So you had to go and remove any remaining doubt and prove that you don't even understand the problem, much less qualify to judge advice about it, by completely missing the point with your supposed analogy above.
You hardly deserve it, but for the benefit of other readers, I'll drop you a hint anyway: in a car analogy, the equivalent of those pointer casts would rather be chewing gum used to patch various gaping holes all across the car's critical systems.
Very droll Dr Jameson. Would you like custard with that banana?
Just because a typecast is there, it does not mean it is bad per se. It is just another component of the language. Like any component of the language, it has advantages, disadvantages and dangers if used incorrectly. A sensible programmer should be aware of all of these issues (and more) if they want to make the best use of those components.
If you put a '+' where a '-' is required, bad things can happen. It may be easier to find a fault like this, but it can still happen and it can still have disasterous results.
A 2005 draft of the C standard requires that casting a pointer derived from one type to one of another type should maintain the alignment correctness for both types (6.3.2.3 Pointers, par. 7):[3]
char *external_buffer = "abcdef"; int *internal_data; internal_data = (int *)external_buffer; // UNDEFINED BEHAVIOUR if "the resulting pointer // is not correctly aligned"
"Just because a typecast is there, it does not mean it is bad per se"
Of course not - and nobody said that. And the point was specifically about pointer casts - not all casts in general.
It was given as an approximation; ie, generally true, but with exceptions.
A type cast is a sign that the data is of the wrong type for the operation being performed on it. True, that's not a problem per se - but, when you see code littered with casts it just has to be a sign that the author really hasn't thought things through. Doesn't it?
Pointer casts are particularly dangerous because the dangers of a mis-cast are so much greater.
Can you honestly be comfortable looking, at a piece of code like this, to think that the author really knows what's going on:
*((double **)(&mat->matrix) + i)
No. IMHO it is just ugly code.
To a very good approximation, every pointer cast in a C program is either superfluous or wrong.
That is what I take issue with! I believe that it is a bad approximation. Pointer casts that are obviously over complex and difficult to interpret with a quick glance are (again IMHO) best avoided. However, there are times where simple pointer casts can be very useful and easy to follow. Just because they are there does NOT make the code wrong, nor does it make the person who uses them a bad programmer.
In my career I have written plenty of code. Some of it uses pointer casts. The code has been functional. The code has worked. The code has been maintainable and maintained by me and others.
Someone stating that pointer casts are superfluous or wrong is going a step too far with the purist bit.
The pragmatic approach has worked for me. I'll stick with it and recommend it.
Nobody denies that.
The assertion is that those instances are the exception, rather than the rule.
"stating that pointer casts are superfluous or wrong is going a step too far"
But nobody said that!
"Someone stating that pointer casts are superfluous or wrong is going a step too far with the purist bit."
You still seem to upgrade a general recommendation into a hard rule.
When implementing abstract data types in C, you normally end up with a void or "base class" pointer that have to be cast to the correct type before being used. And now and then, a C library forgets a C on an input parameter, making it impossible to use your const string without a type cast.
There are a number of situations where type casts of pointers are needed. But real-world code tends to get a lot of pointer casts where the code shouldn't have needed any casts. Too much code tends to look like trial-and-error.
No. Refer back to Broeker's comment and, in particular, the style of that comment.
Tough but fair!
"To a very good approximation, every pointer cast in a C program is either superfluous or wrong" (my emphasis).
He clearly said that it's an approximation - I think that is entirely fair in general, and definitely appropriate to this specific context in particular.
I'll keep all further approximation of the writer's personal traits to myself!
He also wrote: "Next you're putting entirely too many casts into that code." and not "You have casts in that code."
No claim that zero casts are the only allowed count.
Someone see a criticism and get migthy upset, stamp the little feet in the floor and cries.
If you can not handle criticisms, stay away from organized jobs where regular code reviews are the rule. At my first such job I learned a lot and my code became far more 'natural' and thus more mainatainable.
Above (paraphrasing) there is a defensive statement "my code has been maintained by others" SO WHAT. I have maintained much code written by others the diffrence is not whether it was possible, but how much effort it took.
Erik
When implementing abstract data types in C, you normally end up with a void or "base class" pointer that have to be cast to the correct type before being used.
You rather rarely have to. It's generally both clearer and safer to avoid the cast and just assign that (void*) to a variable of the proper type instead.
It's clearer because the new pointer variable will have to be created just once, instead of performing the same pointer cast multiple times.
It's safer because a cast all but forces the compiler to accept whatever type you put in there, since you used the ultimate means of telling it you know exactly what you're doing. So even if that cast can't work at all, e.g. because it breaks const correctness, the compiler may still obey it. The compiler would refuse the same type change if you did it implicitly, on assignment. Any pointer conversion that the compiler wouldn't do implicitly, without asking, is usually ill-advised or unsafe if forced by a cast.
I'm not agreeing on this one. I normally don't want the base implementation to just have raw void* pointers that always have to be assigned to a pointer of a different type even for performing base-class functionality. I normally prefer the base class to have pointers GenericNode *prev,*next so the implementation can do all generic operations directly without an assign or type cast.
So in the end, a type cast will then be needed first when upgrading from the base class element type into the specific type, assuming that the abstract data type is uniform, only containing objects of one single type.
It's important to note that abstract container objects can sometimes be implemented with the assumption that all inserted objects contains any links needed. While it is also possible to create abstract container objects that instead allocate own memory to store links. The second alternative allows you to create a list of int and can work quite well with void* pointers but instead needs own memory allocations for each inserted object. The advantage is of course that a single object can be inserted into many lists. But the costs of such an implementation can be quite high. The list doesn't know the number of elements that may be added, so it can't just statically allocate these helper structures.
Most of the time, I prefer abstract containers that assumes that inserted objects shares a common property, so they may look like:
typedef struct { struct GenericNodeInfo links; MySpecificData xxx; } MySpecificNode;
I normally fix type safety by something like:
threadlist_add(Thread* t) { list_add(threads,(GenericNode*)t); }
and the base class can directly work on the element:
void list_add(GenericList* list,GenericNode *node) { if (!node || !list) { // naughty! return FALSE; } if (node->prev || node->next) { if (!list_unlink(node)) { // node seems to already be in a list - but not in our list... return FALSE; } } node->prev = list->tail; node->next = NULL; list->tail = node; if (!list->head) list->head = node; return TRUE; }
Sometimes, I may extend the above by having the GenericNode object store a value in it representing type, and the container class store the same type. So an insert can complain if a list of "thread" gets an object that isn't of type "thread". Most of the time, this can be done by consuming a single byte (or smaller) since there seldom is a large number of types involved.
But there is no own value in writing code without pointer type casts. The important thing is to reduce the risks of a normally educated developer from goofing up. Someone who really do want to do stupid things will always manage anyway.