C语言 改变符号性的隐式转换在哪里?

qrjkbowd  于 2023-04-11  发布在  其他
关注(0)|答案(2)|浏览(152)

我在处理以下代码时遇到了问题:

#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));
}

当我用Code::Blocks IDE和GNUGCC编译器在我的计算机上运行它时,它没有任何问题。但是当我在另一台机器上使用它时(也用Code:Blocks和LLVM Clang编译器),我得到错误
隐式转换改变符号性:'int'到'unsigned long' [-Werror,-Wsign-conversion]
此错误引用行
char* string =(char*)malloc((number+1)*sizeof(char));
如果我得到的错误消息是正确的,有一些“int”被隐式转换为“unsigned long”,但我没有看到这种情况发生在哪里。
你能给我解释一下吗?

e4eetjau

e4eetjau1#

这是一个警告,编译器认为是由于编译器选项-Werror-Wsign-conversion引起的错误。
在表达式中

(number+1)*sizeof(char)

malloc的调用中使用的操作数sizeof( char )具有无符号整数类型size_t,其是类型unsigned long的别名。另一方面,操作数number+1具有带符号类型int。类型size_t的秩高于类型int的秩。这意味着由于通常的算术转换,int类型的操作数将隐式转换为size_t类型,因此可能会丢失其符号。
要解决这个问题,只需像这样声明函数参数

void someFunction(size_t number);

传递一个有符号的值给分配内存的函数是没有意义的,而且函数malloc的参数的类型是size_t
为了使它清楚,然后考虑下面的简单程序。

#include <stdio.h>

int main( void )
{
    int number = -1;

    printf( "( size_t )number = %zu\n", ( size_t )number );
}

它的输出可能看起来像

( size_t )number = 4294967295

正如你所看到的,类型为int的负变量number被转换为无符号整数类型size_t,变成了一个非常大的无符号整数。

w6lpcovy

w6lpcovy2#

malloc函数的签名是

void* malloc(size_t size);

size_t是一个unsigned整数类型,而int是有符号的。您正在将值(number+1)*sizeof(char)传递给此函数。
clang基本上会问你:如果传入的number的值为负,函数会发生什么?
要摆脱这种情况,要么显式地将number转换为size_t,以告诉编译器您知道它不会为负,要么首先将number的类型更改为size_t
另外请注意,这只是一个错误,因为clang是用-Werror标志调用的(将所有警告视为错误)。否则,这将只是一个 * 警告 *,这意味着程序仍然可以编译,但编译器会通知您潜在的问题。这并不是说-Werror是一个坏主意,事实上,除非您正在进行快速原型开发,否则建议您使用-Werror

注意:在这个特定的例子中,转换实际上已经在 * 乘法 * 的过程中发生了。我的clang给出了以下输出:

main.c:14:40: error: implicit conversion changes signedness: 'int' to 'unsigned long' [-Werror,-Wsign-conversion]
  char* string = (char*) malloc((number+1)*sizeof(char));
                                 ~~~~~~^~ ~

如果你仔细看,它会给number+1(类型为int的操作数)和*(操作符)加下划线。sizeof(char)的类型是size_t(这里显示为等价的unsigned long)。所以要执行乘法,clang已经转换了类型。

相关问题