程序猿之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)

主要内容:无符号和有符号之间转换、两数相加溢出后数值计算

#include <stdio.h> 

/* 这个函数存在潜在漏洞 */
float sum_elements(float a[], unsigned length)
{
	int i;
	float result = 0;

	for(i = 0; i <= length - 1; i++)
	{
		result += a[i];
		printf("a[%d] = %f  \n",i,a[i]);
	}
	return result;
}
int main()
{
	int i = 200 * 300 * 400 * 500;  // int表示20亿左右,无符号就40亿左右
	float j = (3.14 + 1e20) -1e20; // 由于表示精度有限输出结果为0 ,而这条语句输出3.14:float j = 3.14 + (1e20 -1e20);
		                       //  e表示10为低的指数
   	long int a = 1;
    	long long int b =10;

        printf("i = %d\n",i);
	printf("j = %f\n",j);
	printf("a = %ld\n",a);
	printf("b = %ld\n",b);
	printf("\n");

	/* 测试补码*/
	unsigned int u = 4294967295u;
	int tu = (int)u;
	printf("u = %u, tu = %d\n", u, tu);  // 无符号int的最大值和-1的补码是一样的(即无符号Umax和-1的补码相同位表示)
	printf("\n");// 一个有符号数映射为它相应的无符号数时,负数转换成大的正数,非负数保持不变 

	/* 测试转换*/
	short int v = -12345;
	unsigned short uv = (unsigned short) v;  // 强制转换改变数值,但不改变位表示(即 -12345和无符号53191位一样)
	printf("v = %d, uv = %u\n", v, uv);
	printf("\n");

	float c[3];
	sum_elements(c,3);  // 传递0时出错 ,出现无符号和有符号转换问题
	/*小结:表达式中一个数是有符号另一个是无符号,C语言默认转换为无符号,在比较-1<0U时会有问题 */

	/*
		溢出计算,公式见下图
	*/
	short a1 = -65536;
	short b1 = -1;
	printf("\n");
	printf("%d\n",a1+b1);

	return 0;
}

溢出公式:

输出:

时间: 2024-08-21 18:40:38

程序猿之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)的相关文章

程序员之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)

主要内容:无符号和有符号之间转换.两数相加溢出后数值计算 #include <stdio.h> /* 这个函数存在潜在漏洞 */ float sum_elements(float a[], unsigned length) { int i; float result = 0; for(i = 0; i <= length - 1; i++) { result += a[i]; printf("a[%d] = %f \n",i,a[i]); } return resul

程序猿之---C语言细节24(段错误、类型提升、sizeof &#39;A&#39;)

主要内容:段错误.类型提升.sizeof  'A' #include <stdio.h> int main() { union test{ char a[10]; int b; }u; int *p = (int *)&(u.a[1]); // 没有引起总线错误 *p = 17; printf("%d\n",*p); #if 0 int *q = 0; // 引起段错误,在linux中运行可看到段错误,在windows下运行时直接出错 *q = 1; #endif

程序猿之--C语言细节15(预处理命令细节#error、运算符#和##、__FILE__、__LINE__)

主要内容:预处理命令细节#error.运算符#和##.__FILE__.__LINE__ #include <stdio.h> /* 包含这个头文件,并不是将其所有函数都链接进程序*/ /* ##运算符 */ #define MK_ID(n) i##n /* 表示将两个记号连接 */ int MK_ID(1), MK_ID(2),MK_ID(3); /* 预处理后变成int i1,i2,i3;*/ /* 定义多个type##_max函数,函数返回类型和参数类型用define决定 * 如GENE

程序猿之---C语言细节16(看了绝对值,编译类型ANSI C和K&amp;R C类型判断,c编译器类型转换bug的细节)

主要内容:编译类型ANSI C和K&R C类型判断,c编译器bug的细节 #include <stdio.h> int main() { // 例子1 :编译器类型判断 /* * K&R采用无符号保留原则,即当一个无符号类型与ing 或更小的整型混合使用时,结果类型为无符号 * ANSI C采用值保留原则, 即当把几个整数操作数像下面这样混合使用时,结果类型可能为有符号也可能为无符号 * ,结果取决于操作数的类型的相对大小 */ if(-1 < (unsigned cha

程序猿之---C语言细节7

主要内容:检测两个整型相加是否溢出 #include <stdio.h> #include <limits.h> int main(int argc, char *argv[]) { /* * a和b为非负整型变量,检测a+b是否会"溢出" */ // INT_MAX=2147483647 int a=123456789,b=2147483000; /* 方法一: if(a+b < 0) printf("overflow\n"); 错误

程序猿之---C语言细节26(C语言中布尔类型、continue细节、sizeof举例、strlen举例)

主要内容:C语言中布尔类型.continue细节.sizeof举例.strlen举例 一.布尔类型 可能很多人不知道现在C语言已经有了布尔类型:从C99标准开始,类型名字为"_Bool" 在C99标准之前我们常常自己模仿定义布尔类型,常见有以下几种方式: 1.方式一 #define TURE 1 #define FALSE 0 2.方式二 typedef enum {false, true} bool; 3.方式三 typedef int bool 闲int浪费内存,对内存敏感的程序使

程序猿之---C语言细节28(const变量初始化、数组大小用const变量细节、const变量与#define宏、volatile修饰)

主要内容:const变量初始化.数组大小用const变量细节.const变量与#define宏.volatile修饰 一.const变量初始化时必须赋值 二.const变量在C++中可以做数组大小元素.在C中不行,因为它是变量 三.const和#define区别:内存分配 四.volatile修饰一些变量:易被操纵系统.硬件.多线程修改的变量 #include <stdio.h> int main() { /* 测试1 */ const int b; // 不初始化会报错 // b = 2;

程序猿之---C语言细节27(函数无参数时细节、函数默认返回int型证明、return默认还回值、void指针++操作)

主要内容:函数无参数时细节.函数默认返回int型证明.return默认还回值.void指针++操作 一.函数无参数时细节 函数无参数时应该加上void 在c语言中一个函数 void f(); 在使用时传递参数f(2);没有报错,而在c++中则会报错 最好加上void来明确函数是无参数的 二.函数默认返回类型为int型 见下面程序 三.return默认返回1 细节:return不可返回执行栈内存中的指针,因为该内存在函数体结束时自动销毁 四.void 指针++操作 void *p; p++; //

程序猿之---C语言细节(指针和数组细节,&quot;//&quot;的可移植性说明)

主要内容:指针和数组细节,"//"的可移植性说明 #include <stdio.h> int main(int argc, char **argv) { int a[10]={1,2,3,4,5,6,7,8,9,0},*p; #if 0 /* 按移植性来说,在<c语言程序设计--现代方法>指出要用当前注释方法,而不是// 因为一些编译可能不支持 */ // 错误举例 while(*a != 0) { a++; // a++ 相当于a = a+1,不能改变a的值