標籤:style blog http color io ar strong 資料 div
第十三題
int CountBits(unsigned int x) { int count=0; while(x) { count++; x = x&(x-1); } return count; }
知識點講解
關於位元運算的一些例子參考:
http://www.ugcs.caltech.edu/~wnoise/base2.html
題目講解
x&(x-1)常見的兩種應用:
1)計算x二進位形式中1的個數,每迴圈一次,將x二進位形式最右邊的1變成0;
2)判斷x是否是2的冪,若x&(x-1)==0,x為2的冪。
第十四題
Are the following two function prototypes same? int foobar(void); int foobar();The following programs should be of some help in finding the answer: (Compile and run both the programs and see what happens) Program 1: #include <stdio.h> void foobar1(void) { printf("In foobar1\n"); } void foobar2() { printf("In foobar2\n"); } int main() { char ch = ‘a‘; foobar1(); foobar2(33, ch); return 0; }Program 2: #include <stdio.h> void foobar1(void) { printf("In foobar1\n"); } void foobar2() { printf("In foobar2\n"); } int main() { char ch = ‘a‘; foobar1(33, ch); foobar2(); return 0; }
知識點講解
調用foo()時,可以傳入任意個數,任意類型的參數,編譯器不會關心傳給foo的參數,傳入的參數對foo函數的執行沒有影響;
調用foo(void)時,不可傳入參數,否則編譯不通過;
void foo() {}是定義無參數函數的一種過時的用法,故日常編寫代碼時,若函數沒有參數,最好寫成foo(void)的形式。
題目講解
Program 1能編譯通過,運行後正常列印兩個字串;
Program 2編譯不通過,提示foobar1參數過多。
第十五題
What‘s the output of the following program and why? #include <stdio.h> int main() { float a = 12.5; printf("%d\n", a); printf("%d\n", *(int *)&a); return 0; }
知識點講解
- printf中的%f讀取sizeof(double)個位元組;
#include <stdio.h>int main(){ int a = 10, b = 20, c = 30; printf("%f, %d\n", a, b, c); return 0;}
輸出:0.000000, 30
調用printf時,雙引號後面的所有參數從右往左依次入棧,然後將棧中的資料根據雙引號中的格式從低地址向高地址依次讀取並列印出來。
上述代碼調用printf時,c,b,a依次入棧,%f讀取sizeof(double)=8個位元組,
即a,b所佔的地區,轉換成浮點數為0.000000,%d繼續讀取下面4個位元組,即c所佔的地區,轉換為整型數為30。
- printf中傳入的float型參數自動轉換成double型;
#include <stdio.h>int main(){ float a = 1.2; int b = 10; printf("%x, %x, %d\n", a, b); return 0;}
輸出:40000000, 3ff33333, 10
調用printf時,參數a被轉為double型後再傳入printf,printf的前兩個%x讀取的是a所佔的8個位元組,%d讀取的是b所佔的4個位元組。
gcc –S test.c命令可以產生彙編代碼,上例的彙編代碼主體如下:
main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $32, %esp movl $0x3f99999a, %eax movl %eax, 28(%esp) movl $10, 24(%esp) flds 28(%esp) movl $.LC1, %eax movl 24(%esp), %edx movl %edx, 12(%esp) fstpl 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave ret
“flds 28(%esp)”,flds將28(%esp)地址處的單精確度浮點數即0x3f99999a載入到浮點寄存器,“fstpl 4(%esp)”即將浮點寄存器中的浮點數轉換成double型後放到4(%esp)處。
- printf中的%c讀取4個位元組,printf的char型參數先轉換為int再入棧;
#include <stdio.h>int main(){ char a = 97; int b = 20; printf("%c, %d\n", a, b); return 0;}
輸出:a, 20
上述c代碼的彙編代碼主體為:
main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $32, %esp movb $97, 31(%esp) movl $20, 24(%esp) movsbl 31(%esp), %edx movl $.LC0, %eax movl 24(%esp), %ecx movl %ecx, 8(%esp) movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave ret
“movl %edx, 4(%esp)”在棧中壓了4個位元組。
#include <stdio.h>int main(){ char a = ‘a‘; printf("%d, %d\n", sizeof(a), sizeof(‘a‘)); return 0;}
sizeof求類型的大小,sizeof(a)即sizeof(char),sizeof(‘a’)即sizeof(int),‘a’自動轉換為int型。
題目講解
“printf("%d\n", a);”,a轉換為double型再入棧,%d讀取double型資料的低4個位元組;
“printf("%d\n", *(int *)&a);”float佔4個位元組,*(int *)&a將a在記憶體中存放值轉換為整型數後再傳入printf。
浮點數在記憶體中如何表示參考第九題講解。
C puzzles詳解【13-15題】