htons - Converts an unsigned short (16-bit) integer from host byte order to network byte order
Big-endian和Little endian byte order。不同的處理器選擇了不同的byter order,也就是host byte order。但在異構網絡環境裡,這樣無法通信,因此必須採用統一的byte order,這就是network byte order。TCP/IP選用的是big-endian。
FROM INTERNET
http://libai.math.ncu.edu.tw/bcc16/pool/1.33.shtml
用 C 語言窺探記憶體
C 語言可以說是『最低階的高階語言』,它提供許多語法讓人有機會窺探電腦的具體狀況。以下提供程式原始碼,和作者寫此文件當時的執行狀況。這裡不是 C 語言教材,所以不說明 C 的語法,只是用它來示範。這些程式都是標準的 ANSI C 原始碼,可以用任何 C 編譯器製造可執行檔,在讀者自己的機器上做實驗。
以下程式顯示三個變數 c, n 和 str 被配給的記憶體位址。
/* Program A */
#include <stdio.h>
main() {
int c, n;
char str[12];
printf("c is at %u\n", &c);
printf("n is at %u\n", &n);
printf("str is at %u\n", &str);
}
在不同電腦上,甚至於在不同時間,執行這個程式,獲得的數據應當不同。我的手邊有兩部電腦可以用,一部的 CPU 是 Intel Pentium 並以 Linux 為作業系統(主機名是李白),另一部的 CPU 是 Sun UltraSparc 並以 Solaris 為作業系統 (主機名是王維),兩者都屬於 Unix 作業系統。以後,稱前者為 Intel,稱後者為 Sun。 Program A 的執行結果為
Intel Sun
c is at 3221223228
n is at 3221223224
str is at 3221223200 c is at 4026530332
n is at 4026530328
str is at 4026530264
不論 Intel 還是 PC,都看到:先宣告的變數,位址在後面。這就是 data segment 『從後面』排起的效果。以 Intel 為例,而且為了方便我們只寫記憶體位址的後三碼:
c 配給的記憶體是 228, 229, 230, 231 共 4 bytes
n 配給的記憶體是 224, 225, 226, 227 共 4 bytes
str 配給的記憶體是 200, 201, 202, ..., 211 共 12 bytes
現在可以補充兩件書本上沒有仔細說明的現象。
第一,雖然 str[12] 需要存放 12 個 char 型態的數值,而每個 char 的資料含量是 1 byte,所以總共需要 12 bytes,但是 202..223 卻沒有用到,看來 Intel 浪費了 12 bytes。觀察 Sun,更過份,我們只要 12 bytes,但是電腦卻配給了 64 bytes。看來 Sun 浪費了 52 bytes。這種現象是因為電腦為了傳輸的效率,其實並非一次拿一個 byte 到 CPU 的 register 裡面,而是一次拿一個『存取字元』,稱為 word。而每個 word 通常是 2 bytes 或 4 bytes 或 8 bytes。因此,為了配合電路的設計以提昇效率,硬體設計者會選擇浪費一些記憶體空間。實際狀況如何,已經超出計概範圍,只是要讓讀者知道,在如今大型 CPU 上面寫程式,並不需要刻意節省記憶體。
第二,讀者或許發現,似乎在同一部電腦上,甚至同一款作業系統與 CPU 的電腦上,怎麼每次執行 Program A 的結果都一樣?難道每次執行時,空閒記憶體的位址都一樣嗎?這也未免太巧了吧?其實這是因為現在的作業系統都是多人多工的系統,因此,像 Unix 這樣的系統,會分給每一個『同時』執行中的程式一個「虛擬」 (logical) 記憶體,使得每個程式都「感覺」自己是電腦中唯一的程式。這種「抽象」設計其實化簡了整個電腦的管理,只有真正的作業系統知道現在一共有幾個程式在執行,每個執行中的程式分給一個『執行元件』(process),一個 process 就好像一部完整的電腦:有自己的 CPU 和記憶體和周邊設備。而由作業系統分配各 process 實際分配到的 CPU 時間和記憶體空間。因此,前面看到的記憶體位址,其實是 process 內的虛擬位址,而不是硬體上的實際位址。
/* Program C */
#include <stdio.h>
#define MB 1048576
#define MAX 4096
main() {
int n=0;
double *P[MAX];
while (n < MAX) {
P[n] = (double*) malloc(MB);
if (P[n] != NULL)
printf("I got %4dMB of memory\n", ++n);
else {
fprintf(stderr, "Out of Memory\n");
break;
}
}
}
以下是作者剛才執行的結果。這種結果並不表示 Sun 的功能比 Intel 差勁,實在是因為我們的『李白』安裝了比『王維』多得多的記憶體之故。 Program C 的執行結果如下 (... 是作者修改的,以免印出太多不重要的資料)。
Intel Sun
...
I got 2930MB of memory
I got 2931MB of memory
I got 2932MB of memory
Out of Memory
...
I got 69MB of memory
I got 70MB of memory
I got 71MB of memory
Out of Memory
請注意 C 語言會知道作業系統已經沒有記憶體可以給了,但是 C 語言並不會自動輸出任何錯誤訊息。那一句 Out of Memory 是我們自己寫在程式裡面的錯誤訊息。
Program E 的目的是實驗,如果程式想要將數值存進不容許這個 process 使用的記憶體,會發生 Segmentation Fault 訊息。
/* Program E */
#include <stdio.h>
main() {
char str[12];
int n=0;
printf("I claimed for 12 bytes of memory, but I try to assign "
"str[n] for n=0...\n");
while (1) {
str[n]=0;
printf("%5d", n++);
if (!(n%16))
putchar('\n');
}
}
Program E 只宣告了 12 個字元給 str 序列,用來儲存 1-byte 整數資料。但是它卻無止境地指派數值 0 給 str[0], str[1], str[2], str[3], ...。 C 語言不會檢查其實 str[12] 已經超過 CPU 配給的範圍。但是程式也不一定立刻就會出錯。它可以一直執行到超出記憶體容許範圍,然後才會出錯。以下是執行 Program E 的結果 (... 是作者修改的,以免印出太多不重要的資料)。
Intel Sun
...
2208 ... 2219 2220 2221 2222 2223
2224 ... 2235 2236 2237 2238 2239
2240 ... 2251 2252 2253 2254 2255
Segmentation fault
...
1520 ... 1531 1532 1533 1534 1535
1536 ... 1547 1548 1549 1550 1551
1552 ... 1563 1564 1565 1566 1567
Segmentation fault
雖然 Intel 比 Sun 多跑了一陣子,但是都跑不遠。在這個例子裡面,Segmentation fault 不是我們自己寫的錯誤訊息,是作業系統告訴我們的。
現在我們試探電腦的記憶體設計屬於 Big-Endian 還是 Little-Endian。
如果令 n 是 int 型態的變數,令 n 的值為 2562 + 2*256 + 3,則它的位元排列是
00000000000000010000001000000011
將這 32 bits 每 8 bits 組成一個 byte,共應分成四個字元:
00000000 和 00000001 和 00000010 和 00000011
若以無號整數解讀,這四個字元的值應該是
0 和 1 和 2 和 3
CPU 一定會配給連續四個記憶體給 n,但是這四個記憶體,卻有兩種放置四個 byte 的可能順序。如果我們一律按照記憶體位址從小到大的順序來講,則四個記憶體放置的字元可能是
先 00000000 然後 00000001 然後 00000010 最後 00000011
按照這種順序放置的電腦,稱為 Big-Endian (大頭派);也可能是
先 00000011 然後 00000010 然後 00000001 最後 00000000
按照這種順序放置的電腦,稱為 Little-Endian (小頭派)。
為什麼叫『大頭』派?因為電腦把『大』的位數放在『前面』 (記憶體編號小的就是前面)。就好像我們寫十進制數字 123 的意思一百二十三 (100 + 20 + 3),也就是最大位--百位,寫在前面。因此,我們自己屬於『大頭派』。
相反地,如果把『小』的位數放在『前面』,那就是『小頭』派了。如果有一個民族的文字,把 123 解釋成三百二十一 (1 + 20 + 300),那他們就是『小頭派』。阿拉伯文的文字書寫,是從右向左橫寫,但是遇到數字的時候,卻是跟我們一樣從左向右寫。如果阿拉伯人讀文字與數字的時候,都是從右向左讀,則他們會先讀到數字的最小位。在這個意義之下,阿拉伯人是『小頭派』。
以下程式執行上述實驗。它印出變數 n 佔據的四個記憶體,以及它們分別的值 (以 0 到 255 的無號整數表示)。
/* Program F */
#include <stdio.h>
main() {
int n = 256*256+2*256+3;
unsigned char *c;
printf("n = %d\n", n);
c = (unsigned char*) (void*) &n;
printf("n is allocated at\n%11u\t%11u\t%11u\t%11u\n", c, c+1, c+2, c+3);
printf("%11u\t", *c++);
printf("%11u\t", *c++);
printf("%11u\t", *c++);
printf("%11u\n", *c++);
}
執行的報表如下。
Intel
n = 66051
n is allocated at
3221223236 3221223237 3221223238 3221223239
3 2 1 0
Sun
n = 66051
n is allocated at
4026530332 4026530333 4026530334 4026530335
0 1 2 3
我們看到,Intel 的 Pentium CPU 屬於小頭派, Sun 的 Sparc CPU 屬於大頭派。與 Intel 相容的 AMD CPU 也是小頭派,而大部分其他廠牌的 CPU 都是大頭派。 </stdio.h></stdio.h></stdio.h></stdio.h>
2011年9月3日 星期六
2011年8月17日 星期三
2011年8月16日 星期二
UVA 102
最近決定奮發一下,開始寫UVA的題目。
一步一步慢慢挑戰XD
第一題:102Ecological Bin Packing
結果...................狂RE....................
後來去了高中生解題的地方........WA..............
上網找了一下別人寫的答案
一步一步慢慢挑戰XD
第一題:102Ecological Bin Packing
結果...................狂RE....................
後來去了高中生解題的地方........WA..............
上網找了一下別人寫的答案
| /** |
| * UVa 102 Ecological Bin Packing (AC) |
| * Author: http://chchwy.blogspot.com |
| * Last Modified: 2008/09/10 |
| */ |
| #include<iostream> |
| enum{ B=0, C=1, G=2 }; |
| int main() |
| { |
| //六種排列組合 |
| int binColor[][3]={ {B,C,G}, {B,G,C}, {C,B,G}, |
| {C,G,B}, {G,B,C}, {G,C,B} }; |
| char s[][4]={"BCG","BGC","CBG","CGB","GBC","GCB"}; |
| int bin[3][3]; |
| while(scanf("%d%d%d%d%d%d%d%d%d", |
| &bin[0][B],&bin[0][G],&bin[0][C], |
| &bin[1][B],&bin[1][G],&bin[1][C], |
| &bin[2][B],&bin[2][G],&bin[2][C])!=EOF) |
| { |
| int currentMove=0; |
| int totalGlasses=0; |
| for(int i=0;i<3;i++) |
| totalGlasses += (bin[i][B] + bin[i][G] + bin[i][C]); |
| int minMove = totalGlasses; |
| int minNo = 0; //第minNo號排列組合move最少 |
| //六種排列組合都跑過一次 |
| for(int i=0;i<6;i++){ //移動的次數 = 總瓶數-不用移動的瓶數 |
| currentMove = totalGlasses |
| - bin[0][binColor[i][0]] |
| - bin[1][binColor[i][1]] |
| - bin[2][binColor[i][2]]; |
| if(currentMove<minMove){ |
| minMove = currentMove; |
| minNo=i; |
| } |
| } |
| printf("%s %d\n",s[minNo],minMove); |
| } |
| return 0; |
} 再看看我最後終於對的答案 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(){ int x,y,z,min,i, nowV; int xyzV[9],minV[3]; char *tok, represent[3] = {'B', 'G', 'C'}; min = 100000000; while( scanf(" %d %d %d %d %d %d %d %d %d", &xyzV[0], &xyzV[1], &xyzV[2], &xyzV[3], &xyzV[4], &xyzV[5], &xyzV[6], &xyzV[7], &xyzV[8]) == 9 ) { /*tok = strtok(tmp, " "); //while(tok != NULL) {*/ /*sscanf( tmp, " %d %d %d %d %d %d %d %d %d", &xyzV[0], &xyzV[1], &xyzV[2], &xyzV[3], &xyzV[4], &xyzV[5], &xyzV[6], &xyzV[7], &xyzV[8]);*/ /*printf("%d", xyzV[i]);*/ /*}*/ for( x=0 ; ; ) { nowV = 0; nowV = nowV + xyzV[0] + xyzV[1] +xyzV[2] - xyzV[x]; for( y=0 ; ; ) { if( y == x ) { y += 2; y %= 3; if( y == 0 ) break; continue; } nowV = nowV + xyzV[3] + xyzV[4] + xyzV[5] - xyzV[y+3]; for( z=0 ; ; ) { if( z == x || z == y ) { z += 2; z %= 3; if( z == 0 ) break; continue; } nowV = nowV + xyzV[6] + xyzV[7] + xyzV[8] - xyzV[z+6]; if( nowV < min ) { min = nowV; minV[0] = x; minV[1] = y; minV[2] = z; } nowV = nowV - xyzV[6] - xyzV[7] - xyzV[8] + xyzV[z+6]; z+=2; z%=3; if( z == 0 ) break; } nowV = nowV - xyzV[3] - xyzV[4] - xyzV[5] + xyzV[y+3]; y+=2; y%=3; if( y == 0 ) break; } x+=2; x%=3; if( x == 0 ) break; } printf("%c%c%c %d\n", represent[minV[0]], represent[minV[1]], represent[minV[2]], min); min = 1000000000; } return 0; } 真的是弱慘了我............ 紅色部分的就是導致我WA的兇手(忘了還要再扣然後才能再算下個結果)............ |
訂閱:
意見 (Atom)