C语言类型转换规则好复杂?

CJacky++ 2011-08-27 05:28:04
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size指sizeof(?))
1. size大小相同时(符号不同), 内部存储值不变;
2. 大size转化成小size时,内部存储值截取小size部分,高位部分舍弃;
3. 小size转化为大size时,转化成signed类型,表示值保持不变。如果要转成unsigned,再按第1原则将其转化成unsigned.

请问高手,有没有不符合上面原则的,请举个反例,谢谢。

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

void TellMem(void * pData, int size)
{
unsigned char * pBuf;

pBuf = (unsigned char *)pData;
while (size--)
{
printf("%02X ", *pBuf);
pBuf++;
}
printf("\n");
}

int main(void)
{
signed char s8;
unsigned char u8;
signed short s16;
unsigned short u16;
signed int s32;
unsigned int u32;

/* size 相同时, 内部存储值不变 */
s8 = -1;
s16 = -1;
s32 = -1;

u8 = s8;
u16 = s16;
u32 = s32;

TellMem(&s8, sizeof(s8)); // FF
TellMem(&u8, sizeof(u8)); // FF
TellMem(&s16, sizeof(s16)); // FF FF
TellMem(&u16, sizeof(u16)); // FF FF
TellMem(&s32, sizeof(s32)); // FF FF FF FF
TellMem(&u32, sizeof(u32)); // FF FF FF FF

s8 = 1;
s16 = 1;
s32 = 1;

u8 = s8;
u16 = s16;
u32 = s32;

TellMem(&s8, sizeof(s8)); // 01
TellMem(&u8, sizeof(u8)); // 01
TellMem(&s16, sizeof(s16)); // 01 00
TellMem(&u16, sizeof(u16)); // 01 00
TellMem(&s32, sizeof(s32)); // 01 00 00 00
TellMem(&u32, sizeof(u32)); // 01 00 00 00

/* 大size转成小size, 内部存储值截取小size部分,高位部分舍弃 */
s32 = 0x12345678;
s16 = s32;
u16 = s32;
s8 = s16;
u8 = s16;
TellMem(&s32, sizeof(s32)); // 78 56 34 12
TellMem(&s16, sizeof(s16)); // 78 56
TellMem(&u16, sizeof(u16)); // 78 56
TellMem(&s8, sizeof(s8)); // 78
TellMem(&u8, sizeof(u8)); // 78
// 小size转化为大size时,转化成signed类型,表示值保持不变。如果要转成unsigned,再按第1原则将其转化成unsigned.
s8 = -1;
s16 = s8;
u16 = s8;
s32 = s16;
u32 = s16;

printf("%d, %d, %d\n", s8, s16, s32); // -1,-1,-1
TellMem(&s8, sizeof(s8)); // FF
TellMem(&s16, sizeof(s16)); // FF FF
TellMem(&u16, sizeof(u16)); // FF FF
TellMem(&s32, sizeof(s32)); // FF FF FF FF
TellMem(&u32, sizeof(u32)); // FF FF FF FF

system("pause");
return 0;
}


...全文
546 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
CJacky++ 2011-08-30
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 0153 的回复:]
好像不用记这么全,只要掌握最关键的一条就可以了:
凡是有符号型发生扩展,都是带符号扩展(即x86下出现movsx指令)
因为只有这条的结果有可能和编程者的实际想法不一致。
[/Quote]
++++
天亮后说晚安 2011-08-29
  • 打赏
  • 举报
回复
有符号型发生扩展,都是带符号扩展
其他应该大赚小
0153 2011-08-29
  • 打赏
  • 举报
回复
好像不用记这么全,只要掌握最关键的一条就可以了:
凡是有符号型发生扩展,都是带符号扩展(即x86下出现movsx指令)
因为只有这条的结果有可能和编程者的实际想法不一致。
赵4老师 2011-08-29
  • 打赏
  • 举报
回复
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
CJacky++ 2011-08-29
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 supermegaboy 的回复:]
引用 9 楼 cmarquis 的回复:
引用 2 楼 supermegaboy 的回复:
引用楼主 cmarquis 的回复:
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size……
[/Quote]
supermegaboy,能给个不正确例子吗?
CJacky++ 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 anyidan 的回复:]
还原了又怎样,一不小心还是会错的
[/Quote]
规则越简单越不容易出错。我是想归纳一下,作为以后编程的依据。
CJacky++ 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 supermegaboy 的回复:]
引用 9 楼 cmarquis 的回复:
引用 2 楼 supermegaboy 的回复:
引用楼主 cmarquis 的回复:
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size……
[/Quote]
能举个反例吗?
CJacky++ 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 jackyjkchen 的回复:]
没事别乱转,我平均3000行代码出现一次转换
[/Quote]
你说的应该是显式的强制性数据类型转换吧,可是C语言的数据转换无处不在,避无可避的。
显式转换(强制转换): 强制性数据类型转换、利用标准库函数转换
隐式转换(自动转换): 一般算数转换、输出转换(printf)、赋值转换、函数调用转换
AnYidan 2011-08-28
  • 打赏
  • 举报
回复
还原了又怎样,一不小心还是会错的
CJacky++ 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 ljljlj 的回复:]
轿车的刹车都在右侧,麻烦楼主给找个左侧的。
[/Quote]
你想说什么?
ljhhh0123 2011-08-28
  • 打赏
  • 举报
回复
轿车的刹车都在右侧,麻烦楼主给找个左侧的。
飞天御剑流 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 cmarquis 的回复:]
引用 2 楼 supermegaboy 的回复:
引用楼主 cmarquis 的回复:
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size指sizeof(?))
1. size大小……
[/Quote]
你这三条规则都只有部分正确。
CJacky++ 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 supermegaboy 的回复:]
引用楼主 cmarquis 的回复:
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size指sizeof(?))
1. size大小相同时(符号不同), 内部存储值不变;
2. 大s……
[/Quote]
那三个规则是我根据资料抽象出来的,那段代码只是验证那三个规则用的一些例子,当然,没有在所有的编译器,验证所有的情形,所以想问一下高手有没有不适用的例子。
看过别人描述转换的规则,太复杂,不好记,我想还原C语言创造者的最初的思路。不知道这三条规则是否适用?有没有反例?
CJacky++ 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 supermegaboy 的回复:]
引用楼主 cmarquis 的回复:
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size指sizeof(?))
1. size大小相同时(符号不同), 内部存储值不变;
2. 大s……
那段代码只是验证那三个规则用的。看过别人描述转换的规则,太复杂,不好记,我想还原C语言创造的最初的思路。不知道这三条规则是否适用?有没有反例。
暮雨晨舟 2011-08-27
  • 打赏
  • 举报
回复
不明白 帮顶
飞天御剑流 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 luciferisnotsatan 的回复:]
这个不复杂呀,代码写多了自然就知道了。
而且,一般写代码时,都竟然做到类型匹配。而不是在那转来转去的
[/Quote]

转换规则是C/C++最复杂的条款之一。上面贴出来的只是数值转换部分,还有很多其它种类的转换。
飞天御剑流 2011-08-27
  • 打赏
  • 举报
回复
C99:

If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.48) All other types are unchanged by the integer promotions.
The integer promotions preserve value including sign. As discussed earlier, whether a ‘‘plain’’ char is treated as signed is implementation-defined.

6.3.1.2 Boolean type
1 When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.49)
3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

6.3.1.4 Real floating and integer
1 When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.50)
2 When a value of integer type is converted to a real floating type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined.

6.3.1.5 Real floating types
1 When a float is promoted to double or long double, or a double is promoted
to long double, its value is unchanged.
2 When a double is demoted to float, a long double is demoted to double or
float, or a value being represented in greater precision and range than required by its semantic type (see 6.3.1.8) is explicitly converted to its semantic type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined.

6.3.1.6 Complex types
1 When a value of complex type is converted to another complex type, both the real and imaginary parts follow the conversion rules for the corresponding real types.

6.3.1.7 Real and complex
1 When a value of real type is converted to a complex type, the real part of the complex result value is determined by the rules of conversion to the corresponding real type and the imaginary part of the complex result value is a positive zero or an unsigned zero.
2 When a value of complex type is converted to a real type, the imaginary part of the
complex value is discarded and the value of the real part is converted according to the conversion rules for the corresponding real type.

6.3.1.8 Usual arithmetic conversions
1 Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:

First, if the corresponding real type of either operand is long double, the other
operand is converted, without change of type domain, to a type whose corresponding real type is long double.
Otherwise, if the corresponding real type of either operand is double, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is double.
Otherwise, if the corresponding real type of either operand is float, the other
operand is converted, without change of type domain, to a type whose corresponding real type is float.51)
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned
integer types, the operand with the type of lesser integer conversion rank is
converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.
Otherwise, if the type of the operand with signed integer type can represent
all of the values of the type of the operand with unsigned integer type, then
the operand with unsigned integer type is converted to the type of the
operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
2 The values of floating operands and of the results of floating expressions may be
represented in greater precision and range than that required by the type; the types are not changed thereby.52)
jackyjkchen 2011-08-27
  • 打赏
  • 举报
回复
没事别乱转,我平均3000行代码出现一次转换
pathuang68 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 luciferisnotsatan 的回复:]

这个不复杂呀,代码写多了自然就知道了。
而且,一般写代码时,都竟然做到类型匹配。而不是在那转来转去的
[/Quote]

++
飞天御剑流 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用楼主 cmarquis 的回复:]
signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, unsigned long之间的类型转换,是否遵循以下原则?(size指sizeof(?))
1. size大小相同时(符号不同), 内部存储值不变;
2. 大size转化成小size时,内部存储值截取……
[/Quote]
咳,你搞这些代码是白费劲,编译器是给不了你答案的,请看标准的规定:

C89:

6.2.1 Arithmetic operands
6.2.1.1 Characters and integers

A char, a short int. or an int bit-field. or their signed or unsigned varieties. or an enumeration type. may be used in an expression wherever an int or unsigned int may be used If an int can represent all values of the original type. the value is converted to an inf;
otherwise, it is converted to an unsigned int. These are called the integral p~wnotions.” All other arithmetic types are unchanged by the integral promotions.
The integral promotions preserve value including sign. As discussed earlier, whether a “plain” char is treated as signed is implementation-defined.

6.2.1.2 Signed and unsigned integers

When a value with integral type is converted to another integral type, if the value can be represented by the new type, its value is unchanged.
When a signed integer is converted to an unsigned integer with equal or greater size, if the value of the signed integer is nonnegative. its value is unchanged. Otherwise: if the unsigned integer has greater size, the signed integer is first promoted to the signed integer corresponding to the unsigned integer: the value is converted to unsigned by adding to it one greater than the largest number that can be represented in the unsigned integer type ”
When a value with integral type is demoted to an unsigned integer with smaller size, the result is the nonnegative remainder on division by the number one greater than the largest unsigned number that can be represented in the type with smaller size. When a value with integral type is demoted to a signed integer with smaller size. or an unsigned integer is converted to its corresponding signed integer. if the value cannot be represented the result is implementation-defined

6.2.1.3 Floating and integral
When a value of floating type is convened 10 integral type. the fractional part is discarded It the value of the integral pan cannot be represented by the integral type. the behavior iz undetined.”
When a value of integral type is converted to Boating type. if the value being converted is in the range of values that can be represented but cannot be represented exactI>. the result i\ either the nearest hipher or nearest lower value. chosen in an implementation-defined manner

6.2.1.4 Floating types
When a float ih prbmoted to double or long double. or a double is promoted fo
long double. its value is unchanged. When a double is demoted to float or a long double to double or float. if the value being convened is outside the range of values that can be represented. the behavior is undefined. If the value being converted is in the range of values that can be represented but cannot be represented exactly. the result is either the nearest higher or nearest lower value.
chosen in an implementation-delined manner.

6.2.1.5 Usual arithmetic conversions
Many binary operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the rtsual arithmetic cm~ersions:

First. if either operand has type long double, the other operand is converted to long double.
Otherwise, if either operand has type double, the other operand is converted to double.
Otherwise. if either operand has type float, the other operand is converted to float.
Otherwise. the integral promotions are performed on both operands. Then the following rules are applied:
If either operand has type unsigned long int, the other operand is converted to
unsigned long int.
Otherwise. if one operand has rype long int and the other has type unsigned
int. if a long int can represent all values of an unsigned int. the operand of
type unsigned int ih converted to long int; if a long int cannot represent
all the values of an unsigned int, both operands are converted to unsigned
long int
Othcrwtke. if either operand ha\ type long int, the other operand is converted to
long int
Otheruiw. if either operand has type unsigned int. the orher operand i\
converted 10 unsigned int
Othetwiw. horh opcrand~ have type int.
The value of Hoaring operands and of the results of floating expressions may be represented in greater precikn and range than that required by the type; the types are not changed thereby I”
加载更多回复(1)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧