To the question of U-Boot

Find the reason for everything and you will understand a lot.



Recently, looking at the U-Boot code in the part of the SPI implementation, I came across a macro to bypass the list of available devices, which after several transitions reset me to the container_of macro. The macro text itself was present, and with a slight amazement I saw that it was somewhat different from the version I had previously seen. A small investigation was carried out, which led to interesting results.



The macro itself has been known for a long time and solves a somewhat strange problem: we have a pointer to a field of some structure (ptr), we know the type of structure (type) and the name of the field (member), and we need to get a pointer to the structure as a whole. I don’t really understand how such a task could appear, perhaps the authors “wanted something strange,” but once the task is set, it needs to be solved. The solution is well known:



#define container_of(ptr, type, member) \ ((type *)((char *)(ptr)-offsetof(type,member)))
      
      





Everything is transparent and clear, but the discovered implementation was somewhat more complicated:



 #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
      
      





The second line is almost identical to the first solution, but what does the first line of the macro do? No, what it does is just understandable: it creates a constant local pointer to the structure field and assigns it the value of the macro parameter - a pointer to the field. But why this is done is unclear.



An obvious consideration regarding the purpose of the first line is to check the first parameter of the macro that it really is a pointer to a style structure field:



  int *x = (X)
      
      





which in this case takes a somewhat abstruse form:



 typeof( ((type *)0)->member ) *__mptr = (ptr)
      
      





since the type required for verification has to be constructed on the fly.



Okay, let's agree, the thing is useful, however, I had to use the pointer in the second line to avoid compiler warnings.



But why the constancy modifier - the macro should work fine without this addition (I immediately tried and it worked). The authors could not put it by accident.



It’s not necessary to look there
I must admit that they prompted me the answer, I myself did not guess.


It turns out that this modifier is simply necessary if we try to find out the address of the constant structure, because in this case the compiler will need invalid conversion from 'const xxx*' to `xxx*'



.



It is interesting that the constancy of the field itself inside an ordinary structure not only does not require coercion in a macro, but also removes its need for a constant structure, that is, an expression like:



 struct s1 { int data; const int next; }; const struct s1 ss1 = {314,0}; container_of(&(ss1.next),struct s1,next);
      
      





compiles without errors and without a modifier in the macro text, and the expression:



 struct s1 { int data; int next; }; const struct s1 ss1 = {314,0}; container_of(&(ss1.next),struct s1,next);
      
      





it necessarily requires.



For those readers of Habr who know the standard of the language well, my discoveries will seem ridiculous in the style of “Thank you, captain,” but for the rest they may be interesting.



All Articles