c语言--回绕、整数提升

604 篇文章 8 订阅
579 篇文章 5 订阅

C语言是一种弱类型的语言,类型之间可以进行隐式的转换;而C++是强类型的语言,需要进行强制类型转换

Paragraphs6
1、默认参数提升:如果一个函数的形参类型未知,那么调用函数时要对相应的实参做“整数提升(integer promotions)”,除此以外,float类型的参数会被提升为double。
2、如果形参和实参个数不相等的时候,行为未定义;
3、 如果函数定义的时候指定参数原型,那么a)参数原型包含(...),即变参;b)形参类型和实参类型不符合。这两种行为都是未定义的;
4、 如果函数定义的时候不指定参数原型,如果提升后的实参类型和形参类型不相符,则行为未定义;除了两种情况a)提升后一个是unsigned int一个是signed int,则值可以被表示成这两种的任何形式;b)实参或形参都是指针,分别指向限定和非限定(如const)的char或者void。

Paragraphs7
1、 如果一个函数的形参类型已知,则实参的类型会被隐式的转换成形参的类型,并且转换成非限定的对应类型;
2、如果函数原型中有(...)参数,那么对应的实参会被进行默认参数提升;

简单来说,以上标准可以归结为两点:

1、对于有参数原型的函数(非变参),实参会被隐式转换成相应的实参的类型;

2、对于没有参数原型的函数或者变参函数,实参会被进行“默认参数提升”


-------------------------------------------------我是分割线---------------------------------------------------------------

C99规定(无符号整数将会回绕):涉及无符号操作数的计算不会溢出,因为无法由最终的无符号整数类型表示的结果将会根据这种最终类型可以表示的最大值加1执行求模操作。

  这个行为更通俗的说法是无符号整数将会回绕。


如:
unsigned int i = -1;
输出的时候,i 的值为:4294967295(最大值)
i的值有一个循环:
0 1 2 3 。。。 4294967295 0 1 2 。。。。 4294967295 。。。
如果溢出了,就回到循环的开头。

-----------------------------------------------------------我是分割线----------------------------------------------

整数提升


Usual Arithmetic Conversion: 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 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.

献丑翻译成中文:
整数提升:整数提升可以应用于所有的操作数,下面是整数提升的规则:
如果两个操作数具有相同的类型,那么不需要任何的转换;
不然,如果两个操作数同为有符号整数或者同为无符号整数,则rank小的操作数需要被提升为rank大的操作数的类型;
不然,一个无符号操作数的rank大于或者等于另外一个有符号操作数,则该有符号操作数的类型会提升为无符号操作数的类型;
不然,一个有符号操作数可以表示另一个无符号数的所有的值,那么那个无符号操作数的类型需转换为该有符号类型;
不然,两个操作数都需要转换为有符号数对应的无符号类型

-------------------------------------------------------我是分割线------------------------------------------------------------

C语言定义了一系列宏来完成可变参数函数参数的读取和使用:宏va_startva_argva_end;在ANSI C标准下,这些宏定义在stdarg.h中。三个宏的原型如下:

  1. void va_start(va_list ap, last);// 取第一个可变参数(如上述printf中的i)的指针给ap,  
  2.                 // last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);  
  3. type va_arg(va_list ap, type);  // 返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;  
  4.                 // type表示当前可变参数的类型(支持的类型位int和double);  
  5. void va_end(va_list ap);    // 将ap置为NULL  
以下摘自《C陷阱与缺陷》
这里有一个陷阱需要避免:
va_arg宏的第2个参数不能被指定为char、short或者float类型。
因为char和short类型的参数会被转换为int类型,而float类型的参数会被转换为double类型 ……
例如,这样写肯定是不对的:
c = va_arg(ap,char);
因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:
c = va_arg(ap,int);
                ——《C陷阱与缺陷》p164

VC中的三个宏不是已经实现了自动int对齐了吗? 如下:

  1. #define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )  
  2.   
  3. #define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )  
  4. #define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )  
  5. #define va_end(ap)      ( ap = (va_list)0 )  

下面是linux 2.6.22中的实现,其实是一样的意思

  1. #define  _AUPBND                (sizeof (acpi_native_int) - 1)  
  2. #define  _ADNBND                (sizeof (acpi_native_int) - 1)  
  3.   
  4. /* 
  5.  * Variable argument list macro definitions 
  6.  */  
  7. #define _bnd(X, bnd)            (((sizeof (X)) + (bnd)) & (~(bnd)))  
  8. #define va_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))  
  9. #define va_end(ap)              (void) 0  
  10. #define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))  

不过我想说的是:

    C标准对默认实际参数提升规则有明确定。
也就是说, 带有可变长参数列表的函数, 绝对不会接受到char类型的实际参数。

    C标准对va_arg是否自动对齐没有任何说明

也就是说自动对齐工作,编译器可做可不做。

在所有C实现上,能保证第点,不能保证第点,所以尽管编译器实现了自动对齐,也要按标准来。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值