#include <stdio.h> #include <limits.h> int tadd_ok(int x, int y); int tsub_ok(int x, int y); int main(void) { int x, y; x = INT_MAX; y = 3; printf("%d\n", tsub_ok(x, y)); return 0; } int tadd_ok(int x, int y) //后续我的采用的皆是0代表溢出,1代表正常 { int s = x + y; if (x >= 0 && y >= 0) //溢出的可能条件 return s >= 0; else if (x < 0 && y < 0) //溢出的可能条件 return s <= 0; else //不可能溢出 return 1; } int tsub_ok(int x, int y) { return tadd_ok(x, -y); } #include <stdio.h> #include <limits.h> #include <stdint.h> int tmult_ok(int x, int y); int main(void) { int x, y; x = 100; y = INT_MAX; printf("%d\n", tmult_ok(x, y)); return 0; } int tmult_ok(int x, int y) { int64_t p = (int64_t) x * (int64_t) y; //假设int为32bit的拳皇下 return p == (int) p; //当p的int不等于p时,那么说明int存不下p由此发生溢出 } //但是有没有可能在int64_t也发生了溢出,而等于在int中溢出后的值 //我们知道,int*int的最大值为(-2^31)*(-2^31)=2^62,而int64_t最大数为:2^63-1,由此不会放生溢出 //由此当int*int溢出时,p不会溢出,由此p>int64_t(int(p)),即p!=int64_t(int(p)) //由此我们可以证明:x*y发生溢出->p!=int(p),而易知道当p!=int(p)时,x*y溢出 //综上 x*y不溢出<->p=(int)p #include <stdio.h> typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, size_t len) { size_t i; for (i = 0; i < len; i++) printf(" %.2x", start[i]); //start[i]=*(start+i),而i的跨度与&start类型有关,此start为unsigned char*,则i的实际跨度为1byte=8bit=2hex printf("\n"); //而内存单元则为1byte,此输出的时一内存单元里转化为十六进制的二进制数 // } //再者此实验机器采用的小端协议,由此类如0x1234567,则在一段内存中储存为67 45 23 01(4bytes) void show_int(int x) { show_bytes((byte_pointer) &x, sizeof(int)); } void show_float(float x) { show_bytes((byte_pointer) &x, sizeof(float)); } void show_pointer(void *x) { show_bytes((byte_pointer) &x, sizeof(void *)); } void show_double(double x) { show_bytes((byte_pointer)&x, sizeof(double)); } void test_show_bytes(int val) { int ival = val; float fval = (float) ival; //float也为4bytes int *pval = &ival; // int64_t i64_tval = (int64_t) val; //我的gcc太老了,不支持C99 :-( double dval = (double) val; show_int(ival); show_float(fval); show_pointer(pval); // show_bytes(i64_tval); show_double(dval); } void test_len_pointer(void) { printf("the len of pointer is %d\n", sizeof(void*)); //实验机器为4bytes } int main(void) { test_show_bytes(12345); //12345=0x3039 test_len_pointer(); return 0; } /* 编写过程is_little_endian,当在小端法机器上编译和运行时返回1, 在大端法机器上编译运行时则返回0。 这个过程应该可以运行在任何机器上,无论机器的字长是多少。 */ #include <stdio.h> int is_little_endian(void) { int n = 1; //n = 01 00 00 00 int* p = &n; //没搞懂,原因在于无法理解(void*)p的意义 // int* v = (void *) p; //原程序 unsigned char* v = (unsigned char*)p; //我修改的,我认为*v会显示p指向int数据的第一个字节 if (*v == 0x01) //如果是小端的话,则指向01,如果是大端的话,则指向00 return 1; else return 0; } // int main(void) // { // int flag = is_little_endian(); // if (flag == 1) // printf("The Machine is Little Endian\n"); // else if (flag == 0) // printf("The Machine is Big Endian\n"); // else // printf("Something Wrong\n"); // return 0; // } /* 编写一个C表达式,生成一个字,由x的最低有效字节和y中剩下的字节组成。 对于运算数x = 0x89ABCDEF 和 y = 0x76543210,就得到0x765432EF. */ #include <stdio.h> int procedure(int x, int y); int main(void) { printf("%#x\n", procedure(0x89ABCDEF, 0x76543210)); return 0; //%#x的作用是将整数输出为0xxxxxxxx的形式,其中0x的实现是由#符号导致,十六进制的转换是由x的导致 } int procedure(int x, int y) { int mask = 0xFF; //首先我知道二进制掩码的道理,而十六进制的道理可以简化为四位二进制掩码的证明 //0000&xxxx=0000 1111&xxxx=xxxx 由此0&x=0 f&x=x return (~mask & y) | (mask & x); } /* 假设将一个w位的字中的字节从0(最低位)到w/8 - 1(最高位)编号。 //w/8即byte 编写c函数 unsigned replace_byte(unsigned x, int i, unsigned char b); 以下为示例: replace_byte(0x12345678, 2, 0xAB) --> 0x12AB5678 replace_byte(0x12345678, 0, 0xAB) --> 0x123456AB */ // 与 p58.c 一起编译 //why?因为用到了is_little_endian()函数! #include <stdio.h> //链接方法:1.将所需文件生成目标文件 gcc -c filename // 2.将所需目标文件合成生成一个可执行文件 gcc file_1.o ... file_n.o -o name_of_exe unsigned replace_byte(unsigned x, int i, unsigned char b); int is_little_endian(void); int main(void) { getchar(); //ignore return 0; } unsigned replace_byte(unsigned x, int i, unsigned char b) { unsigned int *p = &x; unsigned char *v = (unsigned char *) p; if (is_little_endian()) //这就是可移植性的体现 v[i] = b; //小端低字节在低字节在低地址,高字节在高地址 else v[sizeof(unsigned) - i - 1] = b; return *p; } /* 写一个C表达式,在下列描述的条件下产生1,而在其他情况下得到0。 假设x是int类型。 A. x的任何位都等于1 B. x的任何位都等于0 C. x的最低有效字节中的位都等于1 D. x的最高有效字节中的位都等于0 */ #include <stdio.h> int expression(int x); int xor(unsigned int a, unsigned int b); int main(void) { printf("0xffffffff, %d\n", expression(0xffffffff)); // 情况A printf("0x00000000, %d\n", expression(0x00000000)); // 情况B printf("0x0000000f, %d\n", expression(0x0000000f)); // 情况C printf("0x0fffffff, %d\n", expression(0x0fffffff)); // 情况D printf("0x0f0f0f0f, %d\n", expression(0x0f0f0f0f)); // 情况C D printf("0xfffffff0, %d\n", expression(0xfffffff0)); // 返回0 return 0; } int expression(int x) { int result1, result2, result3, result4; unsigned int mask0 = 0x00000000, mask1 = 0xffffffff, mask3 = 0xf, mask4 = 0xf0000000; result1 = !(xor(x, mask1)); //当x全1,xor后全0,值为0,取反为1 当x不全为1,则xor后不全为0,则值为1,取反为0 result2 = !(xor(x, ~mask1)); //当x全0,xor后全0,值为0,取反为1 当x不全为0,则xor后不全为0,则值为1,取反为0 result3 = !(xor((x & mask3), mask3)); //x&mask4只剩下最低位x存留,当x全1,xor后全0,值为0,取反为1 当x不全为1,则xor后不全为0,则值为1,取反为0 result4 = !(xor((x & mask4), mask0)); //x&mask4只剩下最高位x存留,当x全0,xor后全0,值为0,取反为1 当x不全为0,则xor后不全为0,则值为1,取反为0 // printf("%d %d %d %d\n", result1, result2, result3, result4); return result1 || result2 || result3 || result4; } int xor(unsigned int a, unsigned int b) { return ((a & ~b) | (~a & b)); //a xor b = a & ~b | ~a & b } //注意按位取反与按位and与按位or和取反与and与or的区别 //~ & | //! && || /* 编写一个函数int_shifts_are_arithmetic(),在对int类型的数使用 算术右移的机器上运行这个函数生成1,而其他情况下生成0。 //逻辑右移左补0,算数右移左补原最高位 */ //无符号必为逻辑右移,有符号数看协议 #include <stdio.h> int int_shifts_are_arithmetic(); int main(void) { printf("%d\n", int_shifts_are_arithmetic()); return 0; } int int_shifts_are_arithmetic(void) { int n = -1; //n = 1111 1111 1111 1111 int shifts = (n>>2); //如果是算数的话,则n>>2 = 1111 1111 1111 1111 = -1 = n //如果是逻辑的话,则n>>2 = 0011 1111 1111 1111 = 2^30 - 1 != n // printf("%#x, %#x\n", n, shifts); return shifts == n; //难点在这个n的设置上,妙妙的 : ) } /* 函数srl用算术右移来完成逻辑右移; //logically 函数sra用逻辑右移来完成算术右移。 //arithmetically */ #include <stdio.h> unsigned srl(unsigned x, int k); unsigned sra(int x, int k); int main(void) { int x = 0x12345678; int y = -1; printf("%#x\n", srl((unsigned) x, 8)); printf("%#x\n", sra(x, 8)); printf("%#x\n", srl((unsigned) y, 8)); printf("%#x\n", sra(y, 8)); return 0; } unsigned srl(unsigned x, int k) //accomplish the logical right shift arithmetically { /* perform shift arithmetically */ unsigned xsra = (int) x >> k; //x算数右移k位的二进制码位给xsra int mask = -1; //mask = 1111 1111 1111 1111 //sizeof 返回的为size_t类型的值,size_t可以看作unsigned int mask = mask << ((sizeof(int) << 3) - k); //mask左移(sizeof(int) * 8 - k) 给 mask,得到前k位1,后sizeof(int)*8-k位的0 return ~mask & xsra; //~mask位前k位0,后sizeof(int)*8-k位1,即为保留低sizeof(int)*8-k位的掩码 } //由此致使前k位为0,后sizeof(int)*8-k保留,实现逻辑右移 unsigned sra(int x, int k) //accomplish the arithmetical right shift logically { /* perform shift logically */ int xsrl = (unsigned) x >> k; //前k位0 unsigned mask = 1; //mask = 0000 0000 0000 0001 int *p = &x; char *temp = (void *) p; //貌似void指针会自动转化 // 判断x的最高位是否为1 int h = (((mask << 7) & temp[sizeof(int) - 1]) == 128); //temp[sizeof(int) - 1]在小端中为int 4byte中,以一个byte //0000 0001 0000 0000 & 0000 0000 0000 xxxx h = (-h) << ((sizeof(int) << 3) - k); //真的难懂 :-( return h | xsrl; }