Is this considered as an explicit cast or an (implicit) conversion? - c

As I am working on a topic related to MISRA, I had some doubts about this line of code:
int *a = (int *) malloc( 12 );
as rule 11.5 [A] "A conversion should not be performed from pointer to void into pointer to object" is being raised here.
my question is: is that line of code considered as an explicit cast, or implicit conversion?

Conversions can be either implicit or explicit. An explicit conversion is done using the (type) cast operator. Thus casts are always explicit and there is no such thing as an "implicit cast".
Also using malloc is a massive MISRA C violation in itself, much more serious than the cast.

Related

When are explicit casts actually needed?

Take this code for instance:
const char *s;
char *t = s;
This would emit this: warning: assignment discards 'const' qualifier from pointer target type
It's easy to silence the compiler, by just adding a cast:
char *t = (char*)s;
And you can do similar things for regular variables and not just pointers, and it does not only apply to the const qualifier. You can basically cast from any type to any type, even if some of those casts would cause trouble.
I have also read that you never should cast malloc because a cast to and from void pointer is always safe.
But what does the casting actually do? Does it do something else than just preventing the compiler from spitting out warnings. When are explicit casts actually necessary?
Clarification:
I'm talking about assignments here. Not things like double res = (double)a / b. In that situation, I know what the cast does, and in this case we could easily get rid of the explicit cast in favor of an implicit cast like this: double c = a; double res = c/b; or just double res = (1.0 * a) / b
C 2018 6.5.16.1 1 specifies constraints for the simple assignment operator. For left and right operands that are both pointers other than pointers to void, these say:
One of the following shall hold: … both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right; …
Thus, the C standard requires that pointers be of the same “kind” (compatible types) and that the assignment not remove any qualifiers (the left side has all the qualifiers of the right side, but possibly more). If this requirement is violated, the compiler must issue a diagnostic message (although it can still choose to accept the program; the message can be a warning rather than an error).
6.5.4 specifies constraints for casts, in paragraphs 2 to 4. None of them limit conversions from one pointer type to another. Therefore, you can specify any pointer conversion with a cast, and the compiler is not required to issue a diagnostic (although some may choose to).
The underlying philosophy is that an assignment allows you to implicitly do conversions that are “normal” uses of pointers, but explicitly using a cast allows “special” uses of pointers.
The fact that a particular conversion is allowed with a cast does not necessarily mean it is meaningful or well-defined. 6.3.2.3 defines some rules for conversions of pointers. For example, an int * may be converted to a char *, and the resulting pointer can be used to examine the bytes that represent an int. But converting a char * to an int * may result in undefined behavior. So a cast will allow you to do a conversion, but whether the result is useful or is what you want depends on other rules in the C standard.
When a conversion is allowed and defined, it will have the same effect whether it occurs implicitly by assignment or explicitly by cast. The cast does not change what the conversion is; it only changes whether it is allowed (without a diagnostic) or not.

what is the difference between "int b = (int) 45.0" and "int b = 45.0"?

I have a question.
I was wondering that by adding "(int)" (or any kind of data type), this means that we're converting it into int. ex
double lk = 45.0;
int nm = (int) lk; //not tested though
Anyway, is there a terminology for this?
C in a Nutshell (chapter 4) explains the topic:
In C, operands of different types can be combined in one operation.
[...] When the operands have different types, the compiler tries to
convert them to a uniform type before performing the operation.
This is known as implicit type conversion.
You can also convert values from one type to another explicitly using
the cast operator [...]. You should always use the cast operator
whenever there is a possibility of losing information, as in a
conversion from int to unsigned int, for example. Explicit casts avoid
compiler warnings, and also signpost your program’s type conversions
for other programmers.
This is known as explicit type conversion and is done with the cast operator: (type_name) expression
As n.m. has already pointed pointed out, the result is the same in your example.
Here is another helpful article.

Does setting a void * value to a intptr_t variable require an explicit cast?

I can't seem to make sense of a GCC compiler warning I get when I try to assign a void * value to a intptr_t variable. Specifically, when I compile with -std=c99 -pedantic, I get the following warning regarding the initialization of variable z on line 7:
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
Here is the source code:
#include <stdint.h>
int main(void){
unsigned int x = 42;
void *y = &x;
intptr_t z = y; /* warning: initialization makes integer from pointer without a cast [-Wint-conversion] */
return 0;
}
Naturally, if I explicitly cast y to intptr_t then the warning disappears. However, I confused why the warning is present for implicit conversions when the whole purpose of intptr_t is in the conversion and manipulation of void * values.
From section 7.18.1.4 of the C99 standard:
The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
Am I misinterpreting the standard, or is GCC simply overly pedantic in its "integer from pointer" check in this case?
Summing up! Apologies in advance for any errors — please leave me a comment.
In C99:
Any pointer can be converted to an integer type.1
You might want to do that, e.g., if you are implementing your own operating system!
Conversions between pointers and integers can go horribly wrong,1 so are usually not what you want.
Therefore, the compiler warns you when you convert pointers to integers without casting. This is not overly pedantic, but to save you from undefined behaviour.
intptr_t (and uintptr_t, and likewise throughout) is just an integer type,2 so it is subject to the same risks as any other pointer-to-integer conversion. Therefore, you get the same warning.
However, with intptr_t, you at least know that the conversion from a pointer won't truncate any bits. So those are the types to use — with explicit casts — if you really need the integer values of pointers.
The spec1, #6 says that
... the
result is implementation-defined. If the result cannot be represented in the integer type,
the behavior is undefined.
With intptr_t, the result can be represented in the integer type. Therefore, the behaviour is not undefined, but merely implementation-defined. That is (as far as I know) why those types are safe to use for receiving values from pointers.
Edit
Reference 1, below, is part of section 6.3, "Conversions." The spec says:3
Several operators convert operand values from one type to another automatically. This
subclause specifies the result required from such an implicit conversion...
and refers to section 6.5.4 for a discussion of explicit casts. Therefore, the discussion in Reference 1 indeed covers implicit casts from any pointer type to intptr_t. By my reading, then, an implicit cast from void * to intptr_t is legal, and has an implementation-defined result.1, 4
Regarding whether the explicit cast should be used, gcc -pedantic thinks it should, and there must be a good reason! :) I personally agree that the explicit cast is more clear. I am also of the school of thought that code should compile without warnings if at all possible, so I would add the explicit cast if it were my code.
References
1C99 draft (since I don't have a copy of the final spec), sec. 6.3.2.3 #5 and #6).
2Id., sec. 7.18.1.4
3Id., sec. 6.3
4Id., sec. 3.4.1, defines "implementation-defined behavior" as "unspecified behavior where each implementation documents how the choice is made." The implication is that the conversion is legal, but that the result may be different on one platform than on another.

Is explicit type conversion necessary in A a = (A) b;

I am reading some open-source C code and encountering A a = (A) b; type conversion many times. For example,
static void hexdump(const void* pv, int len)
{
const unsigned char* p = (const unsigned char*) pv;
// some other code
}
A a = (A) b; code happens mainly when b is a pointer, void * pointer most often. I have C++ background. I think in C++, the assignment operator takes= care of the type conversion automatically? Because it already know that a is of type A.
Is the explicit type conversion necessary in C?
No, conversion from void* to char* in C (it's a common example to explain where they're different!) is implicit so casting is unnecessary (then wrong because it may hide a problem if you wrongly change char to int).
Quoting "The C Programming Language, 2nd edition" by K&R (§A.6.8):
Any pointer to an object may be converted to type void* without loss of information. If the result is converted back to the original pointer type, the original pointer is recovered. Unlike the pointer-to-pointer conversions discussed in Par.A.6.6, which generally require an explicit cast, pointers may be assigned to and from pointers of type void*, and may be compared with them.
Please note "If the result is converted back to the original pointer type" because is crucial: if instead of char* you had int* then it may be wrong because of memory alignment.
From C99 standard (§6.3.2.3) about when conversion is possible:
A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
Now let's see when can be implicit (thanks to mafso for very quick search), from C11 (n1570) §6.5.4p3:
Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.
Then §6.5.16.1:
One of the following shall hold: [...] the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right
You've got it the other way around: the cast is absolutely necessary in C++, but it is not necessary in C.
This will compile in C, but not in C++:
static void hexdump(const void* pv, int len) {
const unsigned char* p = pv;
...
}
It is not necessary in C but it helps silent compiler warnings for implicit casts in some cases.
In C++ however you need explicit casts to cast a void pointer into a pointer of a different type.
In my practice, no casting at first, though there's compiler warnings, after testing pass, casting is added to eliminate warnings.
In this case you are making a cast.
You are just saying for the compile. Hey, I'm sure that this is a type (A).
C++ style casts are checked by the compiler. C style casts aren't and can fail at runtime
It's called a cast. It means that it converts b in the (A) type.
char c = 'a'; // c is a char
int b = (int) c // you tell your compiler to interpret c as an int

Casting void pointers

I've seen a lot of the following in older C code:
type_t *x = (type_t *) malloc(...);
What's the point of casting the pointer returned from malloc() since it's void *? Is it because older C compilers didn't support void pointers and malloc() used to return char * instead?
Your own explanation is the right one. Pre-ANSI C ('K&R' C) did not have a void * type with implicit conversion. char * doubled as a pseudo void * type, but you needed the explicit conversion of a type cast.
In modern C the casting is frowned upon because it can suppress compiler warnings for a missing prototype of malloc. In C++, the casting is needed (but there you should be using new instead of malloc most of the time).
Update
My comments below that try to explain why the cast is required were a bit unclear, I'll try to explain it better here. You might think that even when malloc returns char *, the cast is not needed because it is similar to:
int *a;
char *b = a;
But in this example a cast is also needed. The second line is a constraint violation for the simple assignment operator (C99 6.5.1.6.1). Both pointer operands need to be of compatible type. When you change this to:
int *a;
char *b = (char *) a;
the constraint violation disappears (both operands now have type char *) and the result is well-defined (for converting to a char pointer). In the 'reverse situation':
char *c;
int *d = (int *) c;
the same argument hold for the cast, but when int * has stricter alignment requirements than char *, the result is implementation defined.
Conclusion: In the pre-ANSI days the type cast was necessary because malloc returned char * and not casting results is a constraint violation for the '=' operator.
The problem here is not compatibility with any dialect of C. The problem is C++. In C++, a void pointer cannot be automatically converted to any other pointer type. So, without an explicit cast, this code would not compile with a C++ compiler.
I'm not aware that malloc ever returned a char*.
But implicit casting from void* to type_t* (or any other type) hasn't always been allowed.
Hence, the need to explicitly cast to the proper type.
What's the point of casting the pointer returned from malloc() since it's void *?
Quite the contrary. You need to cast a void pointer to an actual type before you can use it, because a void * signifies nothing about the data stored at that location.

Resources