Solved Clang warnings for an invalid casting?

I am trying to compile a simple code (see below) with gcc and clang. the gcc generates a warning indicating an incomparable casting (great!). However, clang didn't generate any warnings! I have passed the same arguments for both:

cc -Wall -Wextra tmp3.c
gcc -Wall -Wextra tmp3.c


Is there an additional option needs to be passed to clang compiler to generate a warning for something that is obviously wrong? The clang documentation isn't a great help!

Code:
int main(void)
{
   void *b = (void *)0x12345678;
   int   a = (int)(unsigned long)b;
   int   c = (int)b;
   return a + c;
}

Clang version 3.8
 
use c++:
c++ -Wall -Wextra tmp3.c
c++: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
tmp3.c:5:12: error: cast from pointer to smaller type 'int' loses information
int c = (int)b;
^~~~~~
1 error generated.
 
In C (int)b is called an explicit conversion, i.e. a cast of which the programmer should be aware of what (s)he is doing.

From what I read about casting in the C11 standard, my feeling is, that it is arguable to emit a warning on an explicit conversion. I usually have all automatic conversion warnings effective when developing in C, and I use explicit casting in order to suppress a specific warning, on amd64 for example int len = (int)strlen(a_string_whose_length_cannot_be_more_than_2GB). I don't like the idea too much that the compiler starts to question all my explicit choices.
 
Interesting! c++ compiler generated an error but cc didn't even give a warning! What does that mean?

I think c is more flexible than c++,you should know what you do, then the compiler just compiles it.While c++ is more strict than c, it add more type check(c++ encourage you to use static_cast etc while the "(type)var" which is c style cast is not encouraged).
 
In C (int)b is called an explicit conversion
I understand (int)b is an explicit conversion but still obviously not right because I am casting a 64-bit to 32-bit without informing the compiler that I know what I'm doing. Consider this assignment
int a = (int)(unsigned long)b;
is explicitly telling the compiler that I know b is bigger than a but I do still want the first 32 bits only.

I do believe there should be a warning for
int c = (int)b;
I think I should report this to clang developers but I wanted to ask for more input form you guys first.

Thank you.
 
you should know what you do
I don't disagree with you on that. However, that is why warnings exist in case someone screwed up something the compiler raises a flag! This is a very fundamental function of a compiler.
 
I have received this response on clang mailing list:

"In C++ mode, Clang errors on the line, same as everyone else. In C mode, however, conversions are typically more permissive. In this case, I suspect Clang should generate this warning as well. It’ll likely require a patch however."
 
Be careful to not get carried away by your enthusiasm.

There are valid use cases for any kind of explicit conversions, and one reason why C programmers use C and not C++ is for being able to explore the flexibility.

For example, if I wanted to know the alignment of a pointer void *ptr, then I could use with clang(1): char alignbits = ((char)ptr & 0xF) ?: 16. gcc6(1) throws a warning, and that already without being asked for, I mean just like that without -Wall -Wextra.

This type of casting is called explicit conversion and the term explicit implies that I WANT the cast exactly as I put it, and without needing to ask the president for permissions. As Jov said, "you should know what you do". To whom this is too much of freedom, might want to use C++ or something alike, anyway, please leave us C programmers with the wishes for more restrictions alone.
 
explicit implies that I WANT the cast exactly as I put it
Understood. I don't disagree with you on what you are saying. However, the casting in
int c = (int)b;
is valid as long as there is no loss of data. That's my point. If b is 64-bit and int is 32-bit then we have a problem. To confirm that I REALLY KNOW WHAT I AM DOING then I need to tell the compiler I know this is 64-bit mapped to 32-bit by adding additional information
int c = (int)(unsigned long)b;

For example, if I wanted to know the alignment of a pointer void *ptr, then I could use with clang(1): char alignbits = ((char)ptr & 0xF) ?: 16. gcc6(1) throws a warning, and that already without being asked for, I mean just like that without -Wall -Wextra.
No really sure how this is relevant to this post.

Thank you, obsigna.
 
Understood. I don't disagree with you on what you are saying. However, the casting in
int c = (int)b;
is valid as long as there is no loss of data. That's my point. If b is 64-bit and int is 32-bit then we have a problem. To confirm that I REALLY KNOW WHAT I AM DOING then I need to tell the compiler I know this is 64-bit mapped to 32-bit by adding additional information
int c = (int)(unsigned long)b;

Did you notice that 0x12345678 is a perfectly valid 32bit int?
For example, if I wanted to know the alignment of a pointer void *ptr, then I could use with clang(1): char alignbits = ((char)ptr & 0xF) ?: 16. gcc6(1) throws a warning, and that already without being asked for, I mean just like that without -Wall -Wextra.
No really sure how this is relevant to this post.
In order to see the relevance, you only need to change int to char in your code, although, in praxis nobody would use this in this way:
Code:
int main(void)
{
   void *b = (void *)0x12345678;
   char  c = (char)b;
   return (b&0xF) ?: 16;
}
This shows the usage of explicit conversion for picking out a small part of the bigger data type. With clang C we may still use it like this without being bugged with nitpickings by the compiler. I never will write idiotic double casts like (int)(unsigned long)ptr. I hope your plea for imposing more restrictions will be refused. I hope further that the contest between GCC and Clang of inventing useless warnings will come to an end soon, since I am already tired of adding all these -Wno-... to the CFLAGS in my Makefiles.

Instead, increase the capabilities of the static analyzer. This one might have found out, that casting (void *)0x12345678 to int in your code example wouldn't lead to any loss of information.
 
Back
Top