二进制数中1的个数是否为奇数

CSAPP第二章家庭作业2.65 /*Return 1 when x contains an odd number of 1s; 0 otherwise. Assume w=32 */ int odd_ones(unsigned x) 函数应该遵循位级整数编码规则,你的代码最多只能包含12个算术运算,位运算和逻辑运算. 代码 先上个代码 int odd_ones(unsigned x) { x ^= x >> 16; x ^= x >> 8; x ^= x >> 4; x ^= x >> 2; x ^= x >> 1; return x & 1; //http://stackoverflow.com/a/9133406 } 在使用循环的情况下就可以不用预先知道int的位数是多少,如下 int odd_ones(unsigned x) { int w = sizeof(x) * 8;//获得x有多少位二进制位,这里是32 int n = 1; while(n < w) { x ^= (x >> n); n <<= 1; } return x & 1; } 原理 由于异或的性质, 可以反映异或对应位上1的个数. 例: 0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 1 = 0. 即只有两位中有奇数个(1个)1的时候, 该位的异或值为1.也就是我们用异或结果的一个位压缩了进行异或的两位的1的个数. 依照这个思想我们可以先写出一个简单的版本: int odd_ones(unsigned x) { unsigned s = x >> 1; while(x) { x ^= s; s >>= 1; } return x & 1; } 我们设最右侧一位为第0位,最左侧一位为第w位, ...

October 12, 2022 · 1 min · 152 words · JuicyMio

C/C++杂项知识点

用于记录一些比较奇怪/少见的c语法/易错易忘点/常见问题, 以备考试等用途 杂项中的杂项 编译没过先看报错信息, 不认识英文请善用翻译 如何提问: 先使用搜索引擎. 如果一定要问人, 附上全部 全部 全部 代码, 以及报错信息 报错信息 报错信息. 和一组出错了的输入输出, 以及注释或你对代码的解释. 因为阅读别人的代码是一件很烧脑的事. 错误示范: 代码截图, 我错哪了? 不要拍屏 查错技巧: 学习使用gdb, 设置断点并查看相关变量的值. 一个低配但很快的方法是用printf输出关键变量 关于CSDN: 虽然内容质量感人被StackOverflow等英文网站甩了十条街, 但还是有一些值得一看的文章的. 而且哪怕用百度查到csdn文章看了也比啥也不查直接问强. 输入数据之后卡住了怎么办: 查看你的代码里是否有死循环, 或者你的输入格式是否合法. 输入输出对不上: 看看格式控制符跟变量类型能否对应, 常见错误是用%f读入double类型变量. 报错信息里有cannot open output file .../*.exe: permission denied或者"无法打开xxx程序进行写入"之类的东西: 你之前的程序没关掉 输出了奇怪的数字: 大概率数组越界 Segmentation fault: 访问了不可访问的内存. 常见原因是数组越界, 指针漂移, 缓冲区溢出, 数组开太大爆栈… 带缺省值的参数需要放在后面, 这样在调用函数的时候就可以不写那个参数. 放在前面编译会报错. int f(int a = 0, int b); // wrong int f(int b, int a = 0); // right 字符串占用的空间要算上 ‘\0’ 关于锟斤拷烫烫烫等成因: 手持两把锟斤拷,口中疾呼烫烫烫,脚踏千朵屯屯屯,笑看万物锘锘锘 锟斤拷 源于GBK字符集和Unicode字符集之间的转换问题。Unicode和老编码体系的转化过程中,肯定有一些字,用Unicode是没法表示的,Unicode官方用了一个占位符来表示这些文字,这就是:U+FFFD REPLACEMENT CHARACTER。那么U+FFFD的UTF-8编码出来,恰好是 ‘\xef\xbf\xbd’。如果这个’\xef\xbf\xbd’,重复多次,例如 ‘\xef\xbf\xbd\xef\xbf\xbd’,然后放到GBK/CP936/GB2312/GB18030的环境中显示的话,一个汉字2个字节,最终的结果就是:锟斤拷——锟(0xEFBF),斤(0xBDEF),拷(0xBFBD)。 ...

October 12, 2022 · 2 min · 225 words · JuicyMio

Pwnable.kr

pwnable.kr writeup 1 fd 文件描述符(file descricptor) 维基百科:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。 习惯上 标准输入(stdin)为0, 标准输出(stdout)为1, 标准错误(stderr)为2. //fd.c #include <stdio.h> #include <stdlib.h> #include <string.h> char buf[32]; int main(int argc, char* argv[], char* envp[]){ if(argc<2){ printf("pass argv[1] a number\n"); return 0; } int fd = atoi( argv[1] ) - 0x1234; int len = 0; len = read(fd, buf, 32); if(!strcmp("LETMEWIN\n", buf)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); } printf("learn about Linux file IO\n"); return 0; } 得到flag的关键在于如何通过第二个if语句, 也就是如何让buf=LETMEMIN 可以看到read从fd中读入32个字节为buf赋值, 如果我们想控制buf的值就要控制fd中的内容, 那么只要让fd=0, 再向标准输入(从命令行直接输入)中输入LETMEWIN就可以了. 注意到fd在此处赋值: int fd = atoi( argv[1] ) - 0x1234; 其中atoi是将字符串转化为整数的函数 int main(int argc, char* argv[], char* envp[]){ 可以看到argv[]是main函数的一个参数, 而main函数的参数都是程序运行时在命令行输入的, argc代表输入参数的个数(第一个参数是程序路径), argv则存储着指向这些参数的指针. envp存储指向环境变量的指针, 此处没用到. 例如运行程序fd ./fd 4660 此时argc值为2, 而argv[0] = “./fd”, argv[1] = “4660” atoi不能转化16进制数, 所以我们手动转换0x1234, 它的十进制表示是4660 这样我们就可以让fd = 0, 程序等待从stdin中读取字符 我们再向命令行中输入LETMEWIN, 即可得到flag ...

October 12, 2022 · 15 min · 3158 words · JuicyMio