Search code examples
ccastingsonarqubevoid

Casting struct* to void*


I have a following function in C:

Bool message(void* msg, unsigned timeout);

and a structure that I want to pass to that function:

msgSPI_t msgSPI; //msgSPI_t is of struct type

like so:

message(&msgSPI, (unsigned)0)

Now, this works as intended, but since I am using SonarQube for code quality inspection, I get a bug for passing &msgSPI:

"Remove this hazardous cast." (according to MISRA C:2004, 11.2 and 11.3).

Since function message is a 3rd party code, I can't (or shouldn't) change it. What would be a good solution here, that would satisfy Sonar complaints? (adding (void*) in front of &msgSPI clears the bug, but I am not sure if that's the correct way to do this.)


Solution

  • I presume this is a length-prefixed block. In a language with inheritance, you'd use something like this:

    class BaseMessage {
       uint32_t size;
    };
    
    class MyMessage extends BaseMessage {
       // ...
    };
    
    bool message( BaseMessage *msg, unsigned timeout );
    
    MyMessage my_message;
    my_message.size = sizeof( MyMessage );
    ...
    
    message( &my_message, timeout );
    

    C doesn't have inheritance. Instead, you tend to see

    bool message( void *msg_body, size_t msg_body_size, unsigned timeout );
    

    But that would require message to build the message, possibly involving a memory allocation. This pattern might be wasteful. And it still uses void *.

    Trying to implement inheritance using unions or whatnot would be messy, and they wouldn't really add any value. You'd just add code and thus complexity to end up with what is effectively just a cast.

    So this is a false positive. These are to be expected from linters, so you should have a process in place to handle these.

    I would prefer a process that flags certain warnings expected, but it could maybe be silenced using the following:

    // Silence SonarQube false positive.
    #define message( msg, timeout ) message( (void*)(msg), (timeout) )
    
    message( &msgSPI, 0U )
    

    I would strongly recommend against using a cast at the call site of each use of message. Pointer casts are dangerous as the defy the type system. The above does have a cast, which is why it's not my preferred approach. But it's only one location, so it's more easily managed.