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 。。。
如果溢出了,就回到循环的开头。
-----------------------------------------------------------我是分割线----------------------------------------------
整数提升
-------------------------------------------------------我是分割线------------------------------------------------------------
C语言定义了一系列宏来完成可变参数函数参数的读取和使用:宏va_start、va_arg和va_end;在ANSI C标准下,这些宏定义在stdarg.h中。三个宏的原型如下:
- void va_start(va_list ap, last);// 取第一个可变参数(如上述printf中的i)的指针给ap,
- // last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);
- type va_arg(va_list ap, type); // 返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;
- // type表示当前可变参数的类型(支持的类型位int和double);
- void va_end(va_list ap); // 将ap置为NULL
这里有一个陷阱需要避免:
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对齐了吗? 如下:
- #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
- #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
- #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
- #define va_end(ap) ( ap = (va_list)0 )
下面是linux 2.6.22中的实现,其实是一样的意思
- #define _AUPBND (sizeof (acpi_native_int) - 1)
- #define _ADNBND (sizeof (acpi_native_int) - 1)
- /*
- * Variable argument list macro definitions
- */
- #define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
- #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
- #define va_end(ap) (void) 0
- #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
不过我想说的是:
① C标准对默认实际参数提升规则有明确规定。
也就是说, 带有可变长参数列表的函数, 绝对不会接受到char类型的实际参数。
② C标准对va_arg是否自动对齐没有任何说明。
也就是说自动对齐工作,编译器可做可不做。
在所有C实现上,能保证第①点,不能保证第②点,所以尽管编译器实现了自动对齐,也要按标准来。