Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 70 additions & 39 deletions ctod.dd
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,14 @@ $(H3 <a name="nans">Dealing with NANs in floating point compares</a>)
$(H4 The C Way)

C doesn't define what happens if an operand to a compare
is NAN, and few C compilers check for it (the Digital Mars
C compiler is an exception, DM's compilers do check for NAN operands).
is `NAN`, and few C compilers check for it (the Digital Mars
C compiler is an exception, DM's compilers do check for `NAN` operands).

$(CCODE
#include &lt;math.h&gt;

if (isnan(x) || isnan(y))
result = FALSE;
result = false;
else
result = (x &lt; y);
)
Expand All @@ -233,9 +233,10 @@ result = (x < y); // false if x or y is nan
$(H3 <a name="assert">Asserts are a necessary part of any good defensive coding strategy</a>)

$(H4 The C Way)
$(P C doesn't directly support assert, but does support __FILE__
and __LINE__ from which an assert macro can be built. In fact,
there appears to be practically no other use for __FILE__ and __LINE__.)
$(P C doesn't directly support assert in the language, but does define a macro
in the standard library header assert.h. That macro writes a diagnostic message
on stderr when the condition given as parameter is not true. The message will
use __FILE__, __LINE__ and __func__ (C99) to localize the failing assertion.)

$(CCODE
#include &lt;assert.h&gt;
Expand Down Expand Up @@ -275,8 +276,8 @@ $(H3 <a name="arrayloop">Looping through an array</a>)

$(H4 The C Way)
$(P
The array length is defined separately, or a clumsy
sizeof() expression is used to get the length.)
The array length is defined separately, or a clumsy and error prone
`sizeof()` expression is used to get the length.)

$(CCODE
#define ARRAY_LENGTH 17
Expand Down Expand Up @@ -343,8 +344,7 @@ int array_length;
int *array;
int *newarray;

newarray = (int *)
realloc(array, (array_length + 1) * sizeof(int));
newarray = realloc(array, (array_length + 1) * sizeof(int));
if (!newarray)
error("out of memory");
array = newarray;
Expand Down Expand Up @@ -380,9 +380,8 @@ char *s2;
char *s;

// Concatenate s1 and s2, and put result in s
free(s);
s = (char *)malloc((s1 ? strlen(s1) : 0) +
(s2 ? strlen(s2) : 0) + 1);
s = malloc((s1 ? strlen(s1) : 0) +
(s2 ? strlen(s2) : 0) + 1);
if (!s)
error("out of memory");
if (s1)
Expand All @@ -394,10 +393,8 @@ if (s2)

// Append "hello" to s
char hello[] = "hello";
char *news;
size_t lens = s ? strlen(s) : 0;
news = (char *)
realloc(s, (lens + sizeof(hello) + 1) * sizeof(char));
char *news = realloc(s, lens + sizeof(hello) + 1);
if (!news)
error("out of memory");
s = news;
Expand Down Expand Up @@ -612,7 +609,9 @@ $(CCODE
void dostring(char *s)
{
enum Strings { Hello, Goodbye, Maybe, Max };
static char *table[] = { "hello", "goodbye", "maybe" };
static char *table[] = { [Hello] ="hello",
[Goodbye]="goodbye",
[Maybe] ="maybe" };
int i;

for (i = 0; i &lt; Max; i++)
Expand All @@ -634,7 +633,9 @@ void dostring(char *s)
structures, the enum, the table, and the switch cases. If there
are a lot of values, the connection between the 3 may not be so
obvious when doing maintenance, and so the situation is ripe for
bugs.
bugs. Designated initializers as were introduced with C99 allow
to link correctly 2 of the 3 data structures, but at the cost of
a lot of typing.

Additionally, if the number of values becomes large, a binary or
hash lookup will yield a considerable performance increase over
Expand Down Expand Up @@ -718,23 +719,23 @@ Sometimes, it's nice to control the layout of a struct with nested structs and u

$(H4 The C Way)

C doesn't allow anonymous structs or unions, which means that dummy tag names
and dummy members are necessary:
Before C11 C didn't allow for anonymous structs or unions, which meant that
dummy member names were necessary:

$(CCODE
struct Foo
{
int i;
union Bar
union
{
struct Abc { int x; long y; } _abc;
struct { int x; long y; } abc;
char *p;
} _bar;
} bar;
};

#define x _bar._abc.x
#define y _bar._abc.y
#define p _bar.p
#define x bar.abc.x
#define y bar.abc.y
#define p bar.p

struct Foo f;

Expand Down Expand Up @@ -839,10 +840,12 @@ $(H4 The C Way)
$(CCODE
union U { int a; long b; };
union U x = { 5 }; // initialize member 'a' to 5
union U y = { .b = 42l }; // initialize member 'b' to 42 (C99)

)

Adding union members or rearranging them can have disastrous consequences
for any initializers.
for any initializers. Designated initializers in C99 fix that issue.

$(H4 The D Way)

Expand All @@ -865,13 +868,15 @@ $(H4 The C Way)
$(CCODE
struct S { int a; int b; };
struct S x = { 5, 3 };
struct S y = { .b=3, .a=5 }; /* C99 */
)

This isn't much of a problem with small structs, but when there
are numerous members, it becomes tedious to get the initializers
carefully lined up with the field declarations. Then, if members are
added or rearranged, all the initializations have to be found and
modified appropriately. This is a minefield for bugs.
modified appropriately. This is a minefield for bugs. Designated
initializers in C99 fix that issue.

$(H4 The D Way)

Expand All @@ -889,9 +894,11 @@ $(H3 <a name="arrayinit2">Array Initializations</a>)

$(H4 The C Way)

C initializes array by positional dependence:
C initializes array by positional dependence. C99 fixes the issue:
$(CCODE
int a[3] = { 3,2,2 };
int a[3] = { 3,2,1 };
int a[3] = { [2]=1, [0]=3, [1]=2 }; /* C99 designated initializer */
int a[3] = { [2]=1, [0]=3, 2 }; /* C99 designated initializer */
)
Nested arrays may or may not have the { }:
$(CCODE
Expand All @@ -901,6 +908,7 @@ int b[3][2] = { 2,3, {6,5}, 3,4 };
$(H4 The D Way)

D does it by positional dependence too, but an index can be used as well.
The D syntax is lighter than C99 designated initializers.
The following all produce the same result:

----------------------------
Expand Down Expand Up @@ -981,9 +989,18 @@ $(CCODE
#include &lt;tchar.h&gt;
tchar string[] = TEXT("hello");
)
Furthermore, in praxis `wchar_t` is not usable in portable code as its size
is implementation dependent. On POSIX conforming machines it generally
represents an UTF-32 codeunit, on Windows an UTF-16 codeunit. C11 introduced
C++11 types char16_t and char32_t to overcome this issue.

$(H4 The D Way)

The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call. Alternatively if type inference is used the string can have a $(B c), $(B w) or $(B d) suffix, representing UTF-8, UTF-16 and UTF-32 encoding, respectively. If no suffix is used the type is inferred to be a UTF-8 string:
The type of a string is determined by semantic analysis, so there is no need
to wrap strings in a macro call. Alternatively if type inference is used the
string can have a `c`, `w` or `d` suffix, representing UTF-8,
UTF-16 and UTF-32 encoding, respectively. If no suffix is used the type is
inferred to be a UTF-8 string:
-----------------------------
string utf8 = "hello"; // UTF-8 string
wstring utf16 = "hello"; // UTF-16 string
Expand All @@ -1004,8 +1021,12 @@ $(H4 The C Way)
$(CCODE
enum COLORS { red, blue, green, max };
char *cstring[max] = {"red", "blue", "green" };
char *cstring[max] = {[red]="red", [blue]="blue", [green]="green" }; /* C99 */
)
This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added.
This is fairly easy to get right because the number of entries is small.
But suppose it gets to be fairly large. Then it can get difficult to
maintain correctly when new entries are added. C99 added designated
initializers to solve that problem.

$(H4 The D Way)
-----------------------------
Expand Down Expand Up @@ -1071,7 +1092,7 @@ if (h != HANDLE_INIT)
$(CCODE
struct Handle__ HANDLE_INIT;

void init_handle() // call this function upon startup
void init_handle(void) // call this function upon startup
{
HANDLE_INIT.value = (void *)-1;
}
Expand All @@ -1087,9 +1108,9 @@ if (memcmp(&amp;h,&amp;HANDLE_INIT,sizeof(Handle)) != 0)

$(H4 The D Way)

D has powerful metaprogramming abilties which allow it to implement
$(D typedef) as a library feature. Simply import $(B std.typecons) and
use the $(B Typedef) template:
D has powerful metaprogramming abilities which allow it to implement
$(D typedef) as a library feature. Simply import `std.typecons` and
use the `Typedef` template:

-----------------------------
import std.typecons;
Expand All @@ -1103,7 +1124,7 @@ foo(h); // syntax error
bar(h); // ok
-----------------------------

To handle a default value, pass the initializer to the $(B Typedef)
To handle a default value, pass the initializer to the `Typedef`
template as the second argument and refer to it with the
$(D .init) property:

Expand Down Expand Up @@ -1230,12 +1251,14 @@ qsort(array, sizeof(array)/sizeof(array[0]),
)

A compare() must be written for each type, and much careful
typo-prone code needs to be written to make it work.
typo-prone code needs to be written to make it work. The indirect function
call required for each comparison limits the achievable performance of the
`qsort()` routine.


$(H4 The D Way)

D has a powerful $(B std.algorithm) module with optimized
D has a powerful `std.algorithm` module with optimized
sorting routines, which work for any built-in or user-defined
type which can be compared:

Expand All @@ -1258,6 +1281,14 @@ $(CCODE
"This text spans\n\
multiple\n\
lines\n"
)

C's string literal concatenation doesn't really solve the problem:

$(CCODE
"This text spans\n"
"multiple\n"
"lines\n"
)

If there is a lot of text, this can wind up being tedious.
Expand Down