在建立struct時,有時候裡面的成員的排序很重要。
排序不同,會造成sizeof整個struct的值不同。
例如以下的例子:
struct aaaaa
{
char a;
int b;
char c;
};
-byte數為12-
struct aaaaa
{
char a;
char c;
int b;
};
-byte數為8-
========== START ==========
struct 的 alignment 有兩個, 首先是個別成員的 alignment, 然後是整個 struct 的 alignment.
首先, 每一個類型都會有它自己的 alignment requirement. 每個物件在記憶體裏的相對位置是:
Offset % alignment-requirement == 0
假定在你的編譯器上, char 的 alignment requirement 是 1, int 的 alignment requirement 是 4.
在第一個 struct 裏, a 是在 offset 0 的位置, 而 b 則須在 offset 4 的位置. a 跟 b 之間會有 3 個 byte 的空格.
個別成員的 alignment 完成後就要做整個 struct 的 alignment. 這個關係到最後一個成員後面要加多少個 padding. 需要這個的原因是當你以 struct 來定義一個陣列的時候, 每一個 struct 元素都需要 align. 這時就要以到 struct 裡面最大的成員來做決定.
所以第一個 struct 最後一個成員 c 後面需要 3 個 bytes 的 padding. 這樣在陣列的架構下, 下一個元素的 b 也會 align:
+=======+
0 |a|x|x|x|
|-------|
4 |b |
|-------|
8 |c|x|x|x|
+=======+
12 |a|x|x|x|
|-------|
16 |b |
|-------|
20 |c|x|x|x|
+=======+
| |
第二個 struct 的 padding 結構:
+=======+
0 |a|c|x|x|
|-------|
4 |b |
+=======+
8 |a|c|x|x|
|-------|
12 |b |
+=======+
而要解決此問題,最好在每一個struct裡面都放相同alignment的變數,
或是使用#pragma pack ()
A1:
#pragma pack(push, 1)
struct aaaaa
{
char a;
char c;
int b;
};
#pragma pack(pop)
其中 "push" 的意思是先將原來的設定(可能是 4)暫存起來;而 "pop" 則是恢復原來的設定。
A2:
#pragma pack(1)
struct aaaaa
{
char a;
char c;
int b;
};
#pragma pack(1)
意思是說,強制把alignment設定為1 byte
參考資料:
Visual C++ 的 Struct Memeber Alignment 問題與解決方法
C/C++ struct 的 alignment
2011年8月29日 星期一
alignment in the C
Bit-field of struct
Bit-field 是一種省空間的特殊 data member, 可以使用特定幾個 bit 來放 data.
#include <stdio.h>
struct Data_Detail
{
unsigned short s1 : 1;
unsigned short s2 : 3;
unsigned short s3 : 4;
unsigned short s4 : 8; // 剛好塞滿一個 16 bit 之 unsigned short
};
typedef struct _Data_View {
char v1 : 1;
char v2 : 1;
char Reserve : 6; // 保留6 bit,當以後需要可以使用
} Data_View;
int
main (
)
{
{
Data_View X;
X.v1 = 0;
X.v2 = 1;
printf ("X.v1 is %d\n", X.v1);
printf ("X.v2 is %d\n", X.v2);
}
{
struct Data_Detail Value;
Value.s1 = 1;
Value.s2 = 2;
Value.s3 = 3;
Value.s4 = 4;
printf ("Value.s1 = %d\n", Value.s1);
printf ("Value.s2 = %d\n", Value.s2);
printf ("Value.s3 = %d\n", Value.s3);
printf ("Value.s4 = %d\n", Value.s4);
}
return 0;
}
建議同一個struct裡面的Bit-field是同一型別,避免因為不同型別而導致錯亂。
若不同的type放在同一個struct裡面,我猜想每一個同型別所需要的空間會算在一起。
例如:
char v1 : 1與char v2 : 1與char Reserve : 6所需要的空間一共是8bit,剛好就是一個char。
所以,用sizeof (Data_View)會是1 (byte)
若在Data_View的結構裡面,加入一個unsigned short s4 : 1
其中unsigned short 是 2 bytes
用sizeof (Data_View)的值會是4,我猜原因是char與unsigned short是分開算的,並且以其中一個最大的為單位,
因為最大是unsigned short是2 bytes,所以,一共是4bytes。
不過,我想這個結果可能跟不同的Compiler不同,而結果有所不同。
參考資料:
Union and Bit-field
2011年8月25日 星期四
在win7下建立一個external partion
在WIN7下,並沒有辦法直接透過Disk Management去分割出一個Extended Boot Record(延伸磁區)
但是,仍然可以透過WIN7內建的指令來建立Extended Boot Record,
1. 透過administrator去開啟cmd
2. > diskpart
3. DISKPART> list disk
4. DISKPART> select disk 0
5. DISKPART> create partition extend size = 40960
6. DISKPART> create partition logical size = 40960
把id改為84
7. DISKPART> list disk
8. DISKPART> select volume = x
9. DISKPART> set id=84 override
其它:
delete partition [noerr] [override]
delete partition 指令可以刪除目前設為焦點的磁碟分割。
Diskpart 不允許刪除目前的系統、開機或分頁磁碟區。若要刪除 ESP、MSR 或已知的 OEM 磁碟分割,您必須指定 override 參數。
參考資料:
[Tutorial] 如何在 Windows Vista / 7 下分割延伸磁區 (Extended Partition) ?
Diskpart 指令行公用程式的說明
2011年8月23日 星期二
讓程式碼的function內的component比較容易被抽換
讓程式碼的function內的component比較容易被抽換
當一個函式很大時,裡面包含許多component,為了程式碼容易看,
在程式中可以透過大括號把一個函式分成許多部分~
如以下的例子:
#include <stdio.h>
int
main (
)
{
int y = 2;
printf ("Hello, Y value is %d\n", y);
#ifdef FOMLOAD
{
int x = 1;
printf ("X value is %d\n", x);
printf ("Y value is %d\n", y);
}
#endif //#ifndef FOMLOAD
// printf ("X value is %d\n", x); // variable x does not exist in this scope
return 0;
}
如此一來,被FOMLOAD包起來的程式碼,就可以依照FOMLOAD在Build Time的時候就決定要不要被執行~
這樣一來程式碼比較容易讀,在抽取的Component時,也比較容易。
另外,在上面的例子中,在大括號被宣告的int x變數,其能被存取的也只有在大括號中。
如此一來,更可以節省一些記憶體的空間。
另外,為了讓程式設計師比對有使用這一個方式跟沒有的差別。
以下是沒有使用這一個大括號的設計方式的程式碼;
#include <stdio.h>
int
main (
)
{
#ifndef FOMLOAD
int x = 1;
#endif //#ifndef FOMLOAD
int y = 2;
printf ("Hello, Y value is %d\n", y);
#ifdef FOMLOAD
printf ("X value is %d\n", x);
printf ("Y value is %d\n", y);
#endif //#ifndef FOMLOAD
// printf ("X value is %d\n", x); // variable x does not exist in this scope
return 0;
}
如此一來,被FOMLOAD被分散在兩個地方,目前這一個例子的程式碼比較小,可能看不出差異,
當程式碼很大時,這兩個部分可能會被分散在好幾行之後(因為,宣告變數一定要在function的開頭)
這樣程式在可讀性上,就比較差。
Makefile
# Program, flags, etc.
CC = cl
CCFLAGS = /c
OBJ = WithCurelyBrace.obj
TARGET = WithCurelyBrace.exe
!IFDEF NOTSHOW
FLAGS =
!ELSE
FLAGS = /DFOMLOAD
!ENDIF
everything: $(TARGET)
clean:
[tab]del $(OBJ) $(TARGET)
all: clean everything
.c.obj:
[tab]$(CC) $(CCFLAGS) $< /Fo$@ $(FLAGS)
$(TARGET): $(OBJ)
[tab]$(CC) $(OBJ) /Fe$@
指令如下:
nmake all NOTSHOW=1
不會顯示括號內的指令
nmake all
會顯示括號內的指令
2011年8月22日 星期一
海報列印軟體
Easy Poster Printer
RonyaSoft Poster Printer
可以印大張的圖片檔
PosteRazor
可以把大張的圖片檔轉成pdf
參考資料:
想印大海報印表機卻不夠大怎麼辦?用Easy Poster Printer來幫你分割列印吧!
免費的海報分割列印軟體 PosteRazor
Portable RonyaSoft Poster Printer 3.01.16 繁中隨身免安裝版