Setting and structure member alignment
C method This is the use of command line options, and this effect will affect the entire program, and if there is a module or library does not recompile, the result will be tragic. To solve this problem, you need to use #pragma:
#pragma pack (1)
Struct ABC
{
...
}
#pragma pack ()
However, whether in theory or actually, # prgma is unmiglable between the compiler.
D. It is clear that the main purpose of setting alignment is to make the data portable, therefore require a portable manner that states the structure.
Struct ABC
{
INT Z; // Z is aligned according to the default mode
Align (1) int x; // x Press byte alignment
Align (4)
{
... // {} Declaration in DWORD Alignment
}
Align (2): // From now on Word Alignment
Int y; // y Follow Word Alignment
}
Anonymous structure and joint sometimes, it is necessary to control the distribution of structures nested in the structure or in the interior.
The way C of C does not allow anonymous structure or a combination, which means you need to use the bidding registration and a member of the 傀儡:
Struct foo
{INT i;
Union Bar
{
Struct ABC {INT X; Long Y; }_ABC;
Char * p;
} _bar;
}
#define x _bar._abc.x
#define y _BAR._ABC.Y
#define p _bar.p
Struct foo f;
f.i;
F.X;
f.y;
f.p;
This is not only awkward, but also uses a macro, it also makes the symbol debugger what the program did, and the macro also occupied the global role domain rather than the structured domain.
D method anonymous structure and combination to control distribution in a more natural way:
Struct foo
{INT I;
union
{
Struct {Int x; long y;}
Char * p;
}
}
Foo f;
f.i;
F.X;
f.y;
f.p;
Declare structural type and variable
The way C can be completed in a statement ended in a semicolon:
Struct foo {Int x; int y;} foo;
Or divide two statements:
Struct foo {Int x; int y;}; // pay attention to ';' '
Struct foo foo;
D 's method structure definition and declaration cannot be completed in a statement:
Struct foo {Int x; int y;} // pay attention to ending at the end; '
Foo foo;
This means the end of ';' can be removed, so that the {} of the struct {} and functions and the {} blocks are different from the semicolon usage.
Get the offset of structural members
The way C is natural, and it has been used in a macro:
#include
Struct foo {int x; int y;};
OFF = OFFSTOF (Foo, Y);
D method offset is only another attribute:
Struct foo {Int x; int y;}
OFF = foo.y.offset;
Union initialization
C combined with the initialization of "First Member" rules:
Union u {Int a; long b;};
Union u x = {5}; // Initialization member A is 5
It is catastrophic for any initialization statements for the results of joint add members or rearrange members. D. In D, initialization that member is explicitly designated:
Union u {Int a; long b;}
U x = {a: 5}
Misunderstandings and maintenance issues are also avoided.
Structure initialization
C The means members are initialized in order in the order within {}:
Struct s {int a; int b;};
Struct s x = {5, 3};
For small structures, this is not a problem, but when the number of members becomes large, carefully arrange the initial value to be cumbersome corresponding to the order of their order. Moreover, if you add or rearrange the member, all initialization statements need to be modified appropriately. This is the Radle area of Bug.
D method can explicitly initialize members:
Struct s {int a; int b;}
S x = {B: 3, A: 5}
This is clear and does not depend on position.
Initialization of array
The way C of C is initialized by the number of positions:
INT A [3] = {3, 2, 2};
The array of sakes can use {} or not {}:
INT B [3] [2] = {2, 3, {6, 5}, 3, 4};
The way D of D is also dependent on position, but can also use indexes, the following statement produces the same result:
INT [3] a = [3, 2, 0];
INT [3] a = [3, 2]; // The initial value not provided is considered 0, like C
INT [3] a = [2: 0, 0: 3, 1: 2];
INT [3] a = [2: 0, 0: 3, 2]; // If not provided, the index is plus one in front of the index
This will be convenient if the subscript of the array is enumerated. Moreover, the order in which the enumeration can be changed, or a new enumeration value can be added:
Enum color {black, red, green}
INT [3] c = [Black: 3, Green: 2, Red: 5];
Needly to initialize the nested array:
INT [2] [3] B = [[2, 3], [6, 5], [3, 4]];
INT [2] [3] B = [[2, 6, 3], [3, 5, 4]]; // Error
Square string
C The way C will encounter problems in the DOS file system because '/' in the string is an escape. If you want to use the file C: / ROOT / FILE.C:
Char file [] = "c: //root/file.c";
If you use this expression, it will be very happy. Consider matching the escape sequence of the quotation marks:
/ "[ ^ //]* (//.[ ^//]* )*"/
In C, the horrible representation is as follows:
Char quotestring [] = "/"[ ^]*(.[ ^]*) *";
D. The string itself is Wysiwyg (see what you get). The escape character is located in another string. and so:
Char [] file = 'c: /root/file.c';
CHAR [] quotestring = / "r" [^ //] *) * "/";
The famous Hello World string becomes:
Char [] hello = "hello world" / N;
ASCII characters vs wide character
Modern programming work requires a simple way to support Wchar strings so that your program can achieve internationalization. The way C of C uses WCHAR_T and adds an L prefix before string:
#include
Char foo_ascii [] = "hello";
Wchar_t foo_wchar [] = l "hello";
If the code needs to be compatible with ASCII and WCHAR, the situation will become worse. Need to use macro to block the difference between ASCII and WCHAR strings:
#include
Tchar string [] = text ("hello");
D's way string is determined by semantic analysis, so it is not necessary to use macro to wrap the strings:
Char [] foo_ascii = "hello"; // String uses ASCII
Wchar [] foo_wchar = "hello"; // String uses Wchar
The same amount of the corresponding array
C's way to consider:
Enum colors {red, blue, green, max};
Char * cstring [max] = {"red", "blue", "green"};
When the number of items is small, it is easy to ensure that it is correct. But if the number is large, it will be difficult to guarantee its correctness when adding new items.
D method
Enum colors {red, blue, green}
Char [] [colors.max 1] cstring =
[
Colors.red: "red",
Colors.blue: "blue",
Colors.green: "Green",
];
Although it is not perfect, it is better.
Create a new TypedEf type
The type C in C is weak, that is, they don't truly introduce a type. The compiler does not distinguish the type of TypeDef and its underlying type.
Typedef void * handle;
Void foo (void *);
Void bar (Handle);
Handle H;
Foo (h); // Unpreciated coding error
BAR (h); // ok
C The solution is to create a slanting structure, the purpose is to get the type check and overload capability of the new type. (Translation: Here, the heavy-duty issue involving C )
Struct Handle__ {void * value;}
TYPEDEF STRUCT HANDLE__ * Handle;
Void foo (void *);
Void bar (Handle);
Handle H;
Foo (h); // Syntax error
BAR (h); // ok
If you want to set a default value for this type, you need to define a macro, a naming specification, then keep this specification:
#define handle_init (Handle) -1)
Handle h = handle_init;
H = func ();
IF (h! = handle_init)
...
For that solutions that use structures, things even become more complicated:
Struct Handle__ Handle_init;
void init_handle () // call this function at the beginning
{
Handle_init.value = (void *) - 1;
}
Handle h = handle_init; h = func ();
IF (Memcmp (& H, & Handle_init, Sizeof (Handle))! = 0)
...
Need to remember four names:
Handle, Handle_init, Struct Handle__ and
Value.
D method does not require the habitual structure above. Just write:
Typedef void * handle;
Void foo (void *);
Void bar (Handle);
Handle H;
Foo (h);
Bar (h);
In order to handle the default, you can add an initial value to the TypeDef, you can use
.init property Access this initial value:
Typedef void * Handle = CAST (VOID *) (- 1);
Handle H;
H = func ();
IF (h! = handle.init)
...
I need to remember a name:
Handle.
Compare structure
C method Although c defines a simple and convenient method for the assignment of the structure:
Struct a x, y;
...
X = Y;
But the comparison between the structure is not supported. Therefore, if it is necessary to compare the equality between the two structural examples:
#include
Struct a x, y;
...
IF (Memcmp (& X, & Y, SIZEOF (STRUCT A)) == 0)
...
Please note that this method is clumsy, and it is not supported by the type check.
Memcmp () has a latent bug. In the distribution of structures, due to alignment, there may be "empty cave". C does not guarantee the value in these cavities, so two different structural examples may have the value of all members, but the results of the comparison are "unequal" due to the existence of garbage in the cavity.
The way D of D is directly and obvious:
A x, y;
...
IF (x == y)
...
Compare string
C The way library function strCMP () is used for this purpose:
Char string [] = "hello";
IF (strCMP (strcmp (strcmp (strCMP (strcmp (strCMP (strinc ") == 0) // string match?
...
The string of C is ending with '/ 0', so since the end of the '/ 0' and C of the end is needed, it is insufficient.
D. Why don't you use == operators?
Char [] string = "hello";
IF (String == "Betty")
...
D string of D is additionally saved. Therefore, the implementation of the string comparison can be much faster than the version of C (the difference between them is like the difference between the MEMCMP () of C with STRCMP ()).
D also supports the comparison operator of the string:
Char [] string = "hello";
IF (String <"betty")
...
This is useful for sorting / lookup.
Array sort
C method Although many C programmers do not tire the bubble sort once, the correct way to use Qsort ():
Int Compare (const void * p1, const void * p2)
{
TYPE * T1 = (Type *) P1;
TYPE * T1 = (Type *) P2;
RETURN * T1 - * T2;
}
TYPE ARRAY [10];
...
Qsort (Array, Sizeof (Array) / Sizeof (Array [0]), SIZEOF (Array [0]), Compare;
A Compare () function must be written for each type, and these work is extremely easy to go wrong.
D method This is probably the easiest way of sorting:
TYPE [] array;
...
Array.Sort; // Sort by array
Access to vulnerability memory
C method If you want to access volatile memory, such as shared memory or memory map I / O, a volatile pointer is required:
Volatile Int * P = address;
i = * P;
D's way D has a volatile statement instead of a type of modifier:
INT * P = Address;
Volatile {i = * p;}
Character string
The way C of C C cannot span more lines, so you need to use '/' to divide the text block into multiple lines:
"THIS TEXT SPANS / N /
Multiple / N /
Lines / N "
This practice is very cumbersome if there are many texts.
D's way string text volume can span multiple lines, as shown below:
"THIS TEXT Spans
Multiple
Lines
"
Therefore, you can simply use the clipper / paste to insert a block in the D source code.
Traverse data structure
C manner consider a function that traverses the recursive data structure. In this example, there is a simple string symbol table. The data structure is a binary tree array. The code requires exhaustion this structure to find a particular string in which it is a unique instance.
To accomplish this job, you need a auxiliary function MEMBERSEARCHX to recursively traverse the whole tree. The auxiliary function needs to read some contexts outside the tree, so create a struct paramblock that points to it with the pointer to improve efficiency.
Struct Symbol
{char * id;
Struct Symbol * Left;
Struct Symbol * Right;
}
Struct paramblock
{char * id;
Struct Symbol * SM;
}
Static void Membersearchx (Struct Paramblock * P, Struct Symbol * S)
{
While (s)
{
IF (strcmp (p-> id, s-> id) == 0)
{
IF (P-> SM)
Error ("Ambiguous MEMBER% S / N", P-> ID);
P-> SM = S;
}
IF (S-> LEFT)
MEMBERSEARCHX (P, S-> LEFT);
s = S-> Right;
}
}
Struct Symbol * Symbol_membersearch (Symbol * Table [], Int TableMax, Char * ID)
{
Struct paramblock PB;
INT I;
Pb.id = ID;
Pb.SM = NULL;
For (i = 0; i { MEMBERSEARCHX (PB, Table [i]); } Return Pb.sm; } D. This is the same algorithm's D version, the amount of code is much less than the last version. Because the nested function can access the variable of the peripheral function, it does not need paramblock or the details of the work of its bookkeeping. Nested auxiliary functions are completely internally used in the use of its functions, improve locality and maintainability. There is no difference in performance of these two versions. Class Symbol {char [] id; Symbol left; Symbol Right; } Symbol Symbol_membersear (Symbol [] Table, Char [] ID) {Symbol SM; Void MembersearchX (Symbol S) { While (s) { IF (id == S.ID) { IF (SM) Error ("Ambiguous Member% S / N", ID); SM = S; } IF (S.Left) MEMBERSEARCHX (S.LEFT); s = s.right; } } For (int i = 0; i { MEMBERSEARCHX (Table [i]); } Return SM; } No symbol right shift C method If the left operating number is a symbol integer type, the right shift operator >> and >> = indicate the right shift; if the left operation is unsigned integer type, right shift operator >> and >> = No symbol right shift. If you want to perform unsigned right on int, you must use the type conversion: INT I, J; ... J = (unsigned) I >> 3; in case i INT, this method will work very well. but if i is a typedef type, Myint i, j; ... J = (unsigned) I >> 3; and Myint happens Long Int, this type of conversion will quietly lose the most important BIT, give an incorrect result. The way D of D. The right movement operator >> and >> = behavior is the same as they in C. However, D also supports explicit right-shifted operators >>> and >>> =, regardless of whether the left operand has a symbol, unsigned right shifts. therefore, Myint i, j; ... J = I >>> 3; Avoid unsafe type conversion and work as you wish for any integer type.