Search code examples
ccompiler-errorsintegerimplicit-conversionsize-t

Where is the implicit conversion that changes signedness?


I am having trouble with the following code:

#include <stdio.h>
#include <stdlib.h>

void someFunction(int number);

int main()
{
    printf("Hello world!\n");
    return 0;
}

void someFunction(int number)
{
  char* string = (char*) malloc((number+1)*sizeof(char));
}

When I run it on my computer with the Code::Blocks IDE and the GNU GCC compiler it works without any problems. But when I use it on another machine (also with Code:Blocks and LLVM Clang Compiler compiler) I get the error

implicit conversion changes signedness: 'int' to 'unsigned long' [-Werror,-Wsign-conversion]

This error refers to the line

char* string = (char*) malloc((number+1)*sizeof(char));

If I get the error message correctly there is some "int" that is implicitly converted to "unsigned long", but I do not see where this happens.

Could you please explain this to me?


Solution

  • It is a warning considered by the compiler as an error due to the compiler options -Werror and -Wsign-conversion.

    Within the expression

    (number+1)*sizeof(char)
    

    used in the call of malloc the operand sizeof( char ) has unsigned integer type size_t that is an alias for the type unsigned long. On the other hand, the operand number+1 has the signed type int. The rank of the type size_t is higher than the rank of the type int. It means that due to the usual arithmetic conversions the operand of the type int will be implicitly converted to the type size_t and thus can lose its sign.

    To resolve the problem just declare the function parameter like

    void someFunction(size_t number);
    

    There is no sense to pass a signed value to the function that allocates memory. And moreover the parameter of the function malloc has the type size_t.

    To make it clear then consider the following simple program.

    #include <stdio.h>
    
    int main( void )
    {
        int number = -1;
    
        printf( "( size_t )number = %zu\n", ( size_t )number );
    }
    

    Its output might look like

    ( size_t )number = 4294967295
    

    As you can see the negative variable number of the type int converted to the unsigned integer type size_t becomes a very big unsigned integer.