C 函数参数从有符号整数到无符号整数的转换

C 函数参数从有符号整数到无符号整数的转换,c,type-conversion,implicit-conversion,C,Type Conversion,Implicit Conversion,在我前几天偶然发现的以下代码片段中,它将带符号int传递给一个需要无符号int的函数 #include "stdio.h" void set_data(unsigned int* addr, const unsigned int data) { printf("Inside set_data:%d\n", data); *addr = data; } int main() { unsigned int a = 2; printf("Before set_dat

在我前几天偶然发现的以下代码片段中,它将
带符号int
传递给一个需要
无符号int
的函数

#include "stdio.h"

void set_data(unsigned int* addr, const unsigned int data)
{
    printf("Inside set_data:%d\n", data);
    *addr = data;
}

int main() {
    unsigned int a = 2;
    printf("Before set_data:%d\n", a);
    set_data(&a, -10);
    printf("After  set_data:%d\n", a);

    return 0;
}
输出:-
注意:编译器没有引发任何警告:-

zhossain@zhossain-linux1:~$ gcc -Wall test.c
zhossain@zhossain-linux1:~$ ./a.out
Before set_data:2
Inside set_data:-10
After  set_data:-10
问题:-
1.为什么编译器不叫喊?隐式转换?
2.为什么“内部集合数据”打印负整数而
数据
被明确定义为
无符号整数

3.是否有可能定义了未定义的行为或实现,这可能不是编写安全可移植代码的良好实践


期待详细解释,如果您能指出相关的SO线程,我也将不胜感激。查看您的代码,我想我理解您的困惑所在。您正在将
-10
作为
无符号
值传递,并且您正在用“如果它是一个`无符号的值,为什么它要打印
-10
”来挠头?”

这一切归结起来都是零碎的。
10
的位是(使用
16
位防止大量零)

在大多数计算机中,负值是以两位补码格式存储的(外行术语是所有位加一的倒数)。如果应用两次,则返回相同的数字。因此,
-10
的两个补码存储是:

1111111111110110
这将很好地适应和
无符号
相同类型的值

下一个难题是“如何打印
-10
?”,只要您的值不超过
int
的最大值,
%d
将愉快地将您提供的位打印为整数。您的代码将
-10
赋值为
int
,然后作为
未签名的
传递是没有问题的,因为您传递的是值
1111110110
。您可以将值打印为
signed int
-10
)或
unsigned int
4294967286

这是您为
printf
回答的唯一问题。它应该如何处理这些位?,“我是将
1111111111111111111111111010
打印为
unsigned
,还是将其打印为
int
。这就是你用
%u
%d
告诉我的
printf

只要您不尝试使用
a
中大于
INT\u MAX
的值作为
INT
,未定义的行为就没有问题。否则,您就可以了


消化这一点,如果我理解了您的担忧,或者我没有理解您的意思,请告诉我,我很乐意提供进一步的帮助。

查看您的代码,我想我理解您的困惑所在。您正在将
-10
作为
未签名的
值传递,您正在用“如果它是一个`无符号值',为什么它要打印
-10

它可以归结为位。
10
的位是(使用
16
位来防止大量的零)

在大多数计算机中,负值以两位补码格式存储(外行术语是所有位加一的倒数)。如果应用两次,则返回相同的数字。因此,
-10
的两位补码存储为:

1111111111110110
这将很好地适应和
无符号
相同类型的值

下一个难题是“如何打印
-10
?”,只要您的值不超过
int
%d的最大值“
将愉快地将您提供的位打印为整数。您的代码将
-10
赋值为
int
,然后作为
未签名的
传递是没有问题的,因为您传递的是值
1111110110
。您可以将值打印为
signed int
-10
)或
unsigned int
4294967286

这是您为
printf
回答的唯一问题。它应该如何处理这些位?,“我是将
1111111111111111111111111010
打印为
unsigned
,还是将其打印为
int
。这就是你用
%u
%d
告诉我的
printf

只要您不尝试使用
a
中大于
INT\u MAX
的值作为
INT
,未定义的行为就没有问题。否则,您就可以了

请消化这一点,如果我理解您的担忧,或者如果我没有理解您的担忧,请告诉我,我很乐意进一步提供帮助。

1)编译器没有“叫喊”(更正确的描述是“发出诊断”)关于隐式转换,因为标准很好地定义了从
有符号
类型到
无符号
类型的转换-它使用(数学上)称为模运算的方法。调用
集_数据(&a,-10)
在调用
集_数据()
。将
-10
值转换为
无符号
时,将产生
UINT_MAX-9
值,其中
UINT_MAX
是从
获得的,表示
无符号int
可以表示的最大值。编译器通常可以配置为发出有关此类转换的警告,但,默认情况下,大多数编译器都配置为不显示警告。如果需要警告,则需要阅读编译器的文档以了解如何显示警告

2) 对
printf()
的所有调用都会导致未定义的行为,因为
%d
通知
printf()
相应的参数的类型为
int
,并且您传递了一个
未签名的
(即类型不匹配)。对于您的特定实现,将
int
类型的值转换为
unsigned
或从
unsigned
类型的值不会更改按位表示,并且传递给
printf()
unsigned
值具有与
int