Ignore:
Timestamp:
Feb 18, 2018, 12:11:24 PM (4 years ago)
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
23a1eb7b
Parents:
c5c4096
Message:

wordsmithing

File:
1 edited

### Legend:

Unmodified
 rc5c4096 \newenvironment{cquote}{% \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}% \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=3pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}% \item\relax }{% Both labelled @continue@ and @break@ are a @goto@ restricted in the following ways: \begin{itemize} \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt] \item They cannot create a loop, which means only the looping constructs cause looping. } \end{cfa} \CFA allows the declaration of local variables, \eg @y@, at the start of the @switch@ with scope across the entire @switch@ body, \ie all @case@ clauses, but no statements. \CFA allows the declaration of local variables, \eg @y@, at the start of the @switch@ with scope across the entire @switch@ body, \ie all @case@ clauses. \CFA disallows the declaration of local variable, \eg @z@, directly within the @switch@ body, because a declaration cannot occur immediately after a @case@ since a label can only be attached to a statement, and the use of @z@ is undefined in @case 1@ as neither storage allocation nor initialization may have occurred. int i; double d; int f() {                                                               $\C{// implicit "this" parameter}$ int f() {                                                               $\C{// implicit this'' aggregate}$ this->c; this->i; this->d;        $\C{// access containing fields}$ } \begin{cfa} void ?{}( S & s, int i ) with ( s ) {           $\C{// constructor}$ s.i = i; j = 3; m = 5.5; s.i = i;  j = 3;  m = 5.5;                    $\C{// initialize fields}$ } \end{cfa} \section{Declarations} It is important that \CFA subjectively feel like'' C to user programmers. It is important that \CFA subjectively feel like'' C to programmers. An important part of this subjective feel is maintaining C's procedural paradigm, as opposed to the object-oriented paradigm of other systems languages such as \CC and Rust. Maintaining this procedural paradigm means that C coding-patterns remain not only functional but idiomatic in \CFA, reducing the mental burden of retraining C programmers and switching between C and \CFA development. \CFA provides its own type, variable and routine declarations, using a different syntax. The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type. The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right. The qualifiers have the same meaning but are ordered left to right to specify a variable's type. \begin{cquote} \lstDeleteShortInline@% \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}}     & \multicolumn{1}{c}{\textbf{C}}        \\ \begin{cfa} int (*x2)[5]; int (*f( int p ))[5]; \end{cfa} & \begin{cfa} // array of 5 pointers to int // pointer to an array of 5 int // function returning pointer to an array of 5 int and taking an int \end{cfa} \end{tabular} \begin{cfa} * int x, y; int y; \end{cfa} & \begin{cfa} int *x, *y; \end{cfa} \end{tabular} \lstMakeShortInline@% \end{cquote} The downside of this semantics is the need to separate regular and pointer declarations: \begin{cquote} \lstDeleteShortInline@% \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}}     & \multicolumn{1}{c}{\textbf{C}}        \\ \begin{cfa} * int x; int y; \end{cfa} & \begin{cfa} int *x, y; \end{cfa} \end{tabular} \lstMakeShortInline@% \end{cquote} which is prescribing a safety benefit. The downside of the \CFA semantics is the need to separate regular and pointer declarations. \begin{comment} & \begin{cfa} double foo1(), foo2( int ), foo3( double ); double foo1( void ), foo2( int ), foo3( double ); \end{cfa} \end{tabular} a value that does not have a corresponding address is called a \newterm{rvalue} (for right-hand value''), while a value that does have an address is called a \newterm{lvalue} (for left-hand value''). For example, in @int x; x = 42;@ the variable expression @x@ on the left-hand-side of the assignment is a lvalue, while the constant expression @42@ on the right-hand-side of the assignment is a rvalue. Despite the nomenclature of left-hand'' and right-hand'', an expression's classification as lvalue or rvalue is entirely dependent on whether it has an address or not; in imperative programming, the address of a value is used for both reading and writing (mutating) a value, and as such lvalues can be converted to rvalues and read from, but rvalues cannot be mutated because they lack a location to store the updated value. Despite the nomenclature of left-hand'' and right-hand'', an expression's classification as lvalue or rvalue is entirely dependent on whether it has an address or not; in imperative programming, the address of a value is used for both reading and writing (mutating) a value, and as such, lvalues can be converted to rvalues and read from, but rvalues cannot be mutated because they lack a location to store the updated value. Within a lexical scope, lvalue expressions have an \newterm{address interpretation} for writing a value or a \newterm{value interpretation} to read a value. For example, in @x = y@, @x@ has an address interpretation, while @y@ has a value interpretation. Though this duality of interpretation is useful, C lacks a direct mechanism to pass lvalues between contexts, instead relying on \newterm{pointer types} to serve a similar purpose. While this duality of interpretation is useful, C lacks a direct mechanism to pass lvalues between contexts, instead relying on \newterm{pointer types} to serve a similar purpose. In C, for any type @T@ there is a pointer type @T *@, the value of which is the address of a value of type @T@. A pointer rvalue can be explicitly \newterm{dereferenced} to the pointed-to lvalue with the dereference operator @*?@, while the rvalue representing the address of a lvalue can be obtained with the address-of operator @&?@. \end{cfa} Unfortunately, the dereference and address-of operators introduce a great deal of syntactic noise when dealing with pointed-to values rather than pointers, as well as the potential for subtle bugs. For both brevity and clarity, it would be desirable to have the compiler figure out how to elide the dereference operators in a complex expression such as the assignment to @*p2@ above. However, since C defines a number of forms of \newterm{pointer arithmetic}, two similar expressions involving pointers to arithmetic types (\eg @*p1 + x@ and @p1 + x@) may each have well-defined but distinct semantics, introducing the possibility that a user programmer may write one when they mean the other, and precluding any simple algorithm for elision of dereference operators. To solve these problems, \CFA introduces reference types @T&@; a @T&@ has exactly the same value as a @T*@, but where the @T*@ takes the address interpretation by default, a @T&@ takes the value interpretation by default, as below: Unfortunately, the dereference and address-of operators introduce a great deal of syntactic noise when dealing with pointed-to values rather than pointers, as well as the potential for subtle bugs because of pointer arithmetic. For both brevity and clarity, it is desirable for the compiler to figure out how to elide the dereference operators in a complex expression such as the assignment to @*p2@ above. However, since C defines a number of forms of \newterm{pointer arithmetic}, two similar expressions involving pointers to arithmetic types (\eg @*p1 + x@ and @p1 + x@) may each have well-defined but distinct semantics, introducing the possibility that a programmer may write one when they mean the other, and precluding any simple algorithm for elision of dereference operators. To solve these problems, \CFA introduces reference types @T &@; a @T &@ has exactly the same value as a @T *@, but where the @T *@ takes the address interpretation by default, a @T &@ takes the value interpretation by default, as below: \begin{cfa} &r2 = &y;  $\C{// r2 points to y}$ &&r3 = &&r1;  $\C{// r3 points to r2}$ r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15);  $\C{// implicit dereferencing}$ r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15);       $\C{// implicit dereferencing}$ \end{cfa} Except for auto-dereferencing by the compiler, this reference example is exactly the same as the previous pointer example. Hence, a reference behaves like a variable name -- an lvalue expression which is interpreted as a value, but also has the type system track the address of that value. Hence, a reference behaves like a variable name -- an lvalue expression which is interpreted as a value -- but also has the type system track the address of that value. One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in the reference variable declaration, so the previous example implicitly acts like: \end{cfa} References in \CFA are similar to those in \CC, but with a couple important improvements, both of which can be seen in the example above. Firstly, \CFA does not forbid references to references, unlike \CC. References in \CFA are similar to those in \CC, with important improvements, which can be seen in the example above. Firstly, \CFA does not forbid references to references. This provides a much more orthogonal design for library implementors, obviating the need for workarounds such as @std::reference_wrapper@. Secondly, unlike the references in \CC which always point to a fixed address, \CFA references are rebindable. This allows \CFA references to be default-initialized (\eg to a null pointer), and also to point to different addresses throughout their lifetime. This rebinding is accomplished without adding any new syntax to \CFA, but simply by extending the existing semantics of the address-of operator in C. Secondly, \CFA references are rebindable, whereas \CC references have a fixed address. \newsavebox{\LstBox} \begin{lrbox}{\LstBox} \lstset{basicstyle=\footnotesize\linespread{0.9}\sf} \begin{cfa} int & r = *new( int ); ... delete &r; r += 1;                 // undefined reference \end{cfa} \end{lrbox} Rebinding allows \CFA references to be default-initialized (\eg to a null pointer\footnote{ While effort has been put into non-null reference checking in \CC, the exercise seems moot for any non-managed languages, given that it only handles one of many different error situations: \begin{cquote} \usebox{\LstBox} \end{cquote} }% ) and point to different addresses throughout their lifetime, like pointers. Rebinding is accomplished by extending the existing syntax and semantics of the address-of operator in C. In C, the address of a lvalue is always a rvalue, as in general that address is not stored anywhere in memory, and does not itself have an address. In \CFA, the address of a @T&@ is a lvalue @T*@, as the address of the underlying @T@ is stored in the reference, and can thus be mutated there. In \CFA, the address of a @T &@ is a lvalue @T *@, as the address of the underlying @T@ is stored in the reference, and can thus be mutated there. The result of this rule is that any reference can be rebound using the existing pointer assignment semantics by assigning a compatible pointer into the address of the reference, \eg @&r1 = &x;@ above. This rebinding can occur to an arbitrary depth of reference nesting; loosely speaking, nested address-of operators will produce an lvalue nested pointer up to as deep as the reference they're applied to. This rebinding occurs to an arbitrary depth of reference nesting; loosely speaking, nested address-of operators produce a nested lvalue pointer up to the depth of the reference. These explicit address-of operators can be thought of as cancelling out'' the implicit dereference operators, \eg @(&*)r1 = &x@ or @(&(&*)*)r3 = &(&*)r1@ or even @(&*)r2 = (&*)*r3@ for @&r2 = &r3@. More precisely: \begin{itemize} \item if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) than @&R@ has type {@T *&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols). \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt] \item if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) than @&R@ has type {@T *&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols). \item if @L@ is an lvalue of type {@T &@$_1 \cdots$@ &@$_l$} where $l \ge 0$ references (@&@ symbols) then @&L@ has type {@T *&@$_{\color{red}1} \cdots$@ &@$_{\color{red}l}$}, \\ \ie @T@ pointer with $l$ references (@&@ symbols). \item if @L@ is an lvalue of type {@T &@$_1 \cdots$@ &@$_l$} where $l \ge 0$ references (@&@ symbols) then @&L@ has type {@T *&@$_{\color{red}1} \cdots$@ &@$_{\color{red}l}$}, \\ \ie @T@ pointer with $l$ references (@&@ symbols). \end{itemize} Since pointers and references share the same internal representation, code using either is equally performant; in fact the \CFA compiler converts references to pointers internally, and the choice between them in user code can be made based solely on convenience. Since pointers and references share the same internal representation, code using either is equally performant; in fact the \CFA compiler converts references to pointers internally, and the choice between them is made solely on convenience, \eg many pointer or value accesses. By analogy to pointers, \CFA references also allow cv-qualifiers such as @const@: \begin{cfa} const int cx = 5;               $\C{// cannot change cx}$ const int & cr = cx;    $\C{// cannot change cr's referred value}$ &cr = &cx;                              $\C{// rebinding cr allowed}$ cr = 7;                                 $\C{// ERROR, cannot change cr}$ int & const rc = x;             $\C{// must be initialized, like in \CC}$ &rc = &x;                               $\C{// ERROR, cannot rebind rc}$ rc = 7;                                 $\C{// x now equal to 7}$ \end{cfa} \begin{cfa} const int cx = 5;                                                       $\C{// cannot change cx}$ const int & cr = cx;                                            $\C{// cannot change cr's referred value}$ &cr = &cx;                                                                      $\C{// rebinding cr allowed}$ cr = 7;                                                                         $\C{// ERROR, cannot change cr}$ int & const rc = x;                                                     $\C{// must be initialized, like in \CC}$ &rc = &x;                                                                       $\C{// ERROR, cannot rebind rc}$ rc = 7;                                                                         $\C{// x now equal to 7}$ \end{cfa} Given that a reference is meant to represent a lvalue, \CFA provides some syntactic shortcuts when initializing references. There are three initialization contexts in \CFA: declaration initialization, argument/parameter binding, and return/temporary binding. In each of these contexts, the address-of operator on the target lvalue may (in fact, must) be elided. The syntactic motivation for this is clearest when considering overloaded operator-assignment, \eg @int ?+=?(int &, int)@; given @int x, y@, the expected call syntax is @x += y@, not @&x += y@. More generally, this initialization of references from lvalues rather than pointers is an instance of a lvalue-to-reference'' conversion rather than an elision of the address-of operator; this conversion can actually be used in any context in \CFA an implicit conversion would be allowed. In each of these contexts, the address-of operator on the target lvalue is elided. The syntactic motivation is clearest when considering overloaded operator-assignment, \eg @int ?+=?(int &, int)@; given @int x, y@, the expected call syntax is @x += y@, not @&x += y@. More generally, this initialization of references from lvalues rather than pointers is an instance of a lvalue-to-reference'' conversion rather than an elision of the address-of operator; this conversion is used in any context in \CFA where an implicit conversion is allowed. Similarly, use of a the value pointed to by a reference in an rvalue context can be thought of as a reference-to-rvalue'' conversion, and \CFA also includes a qualifier-adding reference-to-reference'' conversion, analogous to the @T *@ to @const T *@ conversion in standard C. The final reference conversion included in \CFA is rvalue-to-reference'' conversion, implemented by means of an implicit temporary. When an rvalue is used to initialize a reference, it is instead used to initialize a hidden temporary value with the same lexical scope as the reference, and the reference is initialized to the address of this temporary. \begin{cfa} struct S { double x, y; }; int i, j; void f( int & i, int & j, S & s, int v[] ); f( 3, i + j, (S){ 1.0, 7.0 }, (int [3]){ 1, 2, 3 } );   $\C{// pass rvalue to lvalue $$\Rightarrow$$ implicit temporary}$ \end{cfa} This allows complex values to be succinctly and efficiently passed to functions, without the syntactic overhead of explicit definition of a temporary variable or the runtime cost of pass-by-value. \CC allows a similar binding, but only for @const@ references; the more general semantics of \CFA are an attempt to avoid the \newterm{const hell} problem, in which addition of a @const@ qualifier to one reference requires a cascading chain of added qualifiers. \subsection{Constructors and Destructors} One of the strengths of C is the control over memory management it gives programmers, allowing resource release to be more consistent and precisely timed than is possible with garbage-collected memory management. However, this manual approach to memory management is often verbose, and it is useful to manage resources other than memory (\eg file handles) using the same mechanism as memory. \CC is well-known for an approach to manual memory management that addresses both these issues, Resource Aquisition Is Initialization (RAII), implemented by means of special \newterm{constructor} and \newterm{destructor} functions; we have implemented a similar feature in \CFA. While RAII is a common feature of object-oriented programming languages, its inclusion in \CFA does not violate the design principle that \CFA retain the same procedural paradigm as C. In particular, \CFA does not implement class-based encapsulation: neither the constructor nor any other function has privileged access to the implementation details of a type, except through the translation-unit-scope method of opaque structs provided by C. In \CFA, a constructor is a function named @?{}@, while a destructor is a function named @^?{}@; like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @x{ ... };@ or @^x{};@. Every constructor and destructor must have a return type of @void@, and its first parameter must have a reference type whose base type is the type of the object the function constructs or destructs. This first parameter is informally called the @this@ parameter, as in many object-oriented languages, though a programmer may give it an arbitrary name. Destructors must have exactly one parameter, while constructors allow passing of zero or more additional arguments along with the @this@ parameter. \begin{cfa} struct Array { int * data; int len; One of the strengths (and weaknesses) of C is control over memory management, allowing resource release to be more consistent and precisely timed than possible with garbage-collected memory-management. However, this manual approach is often verbose, furthermore it is useful to manage resources other than memory (\eg file handles) using the same mechanism as memory. \CC addresses these issues using Resource Aquisition Is Initialization (RAII), implemented by means of \newterm{constructor} and \newterm{destructor} functions; \CFA adopts constructors and destructors (and @finally@) to facilitate RAII. While constructors and destructors are a common feature of object-oriented programming-languages, they are independent capabilities allowing \CFA to retain a procedural paradigm. Specifically, \CFA constructors and destructors are denotes by name and first parameter-type versus name and nesting in an aggregate type. In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@; like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @x{ ... };@ or @^x{...};@. The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = { 2, 3 }@. The constructor and destructor have return type @void@ and a first parameter of reference to the object type to be constructed or destructs. While the first parameter is informally called the @this@ parameter, as in object-oriented languages, any variable name may be used. Both constructors and destructors allow additional parametes after the @this@ parameter for specifying values for initialization/de-initialization\footnote{Destruction parameters are useful for specifying storage-management actions, such as de-initialize but not de-allocate.}. \begin{cfa} struct VLA { int len, * data; }; void ?{}( Array& arr ) { arr.len = 10; arr.data = calloc( arr.len, sizeof(int) ); } void ^?{}( Array& arr ) { free( arr.data ); } { Array x; ?{}(x);       $\C{// implicitly compiler-generated}$ void ?{}( VLA& vla ) with ( vla ) {                     $\C{// default constructor}$ len = 10;  data = calloc( len ); } void ^?{}( VLA& vla ) {                                         $\C{// destructor}$ free( vla.data ); } {       VLA x; ?{}(x);                                                $\C{// compiler generated constructor call}$ // ... use x ^?{}(x);      $\C{// implicitly compiler-generated}$ } \end{cfa} In the example above, a \newterm{default constructor} (\ie one with no parameters besides the @this@ parameter) and destructor are defined for the @Array@ struct, a dynamic array of @int@. @Array@ is an example of a \newterm{managed type} in \CFA, a type with a non-trivial constructor or destructor, or with a field of a managed type. As in the example, all instances of managed types are implicitly constructed upon allocation, and destructed upon deallocation; this ensures proper initialization and cleanup of resources contained in managed types, in this case the @data@ array on the heap. ^?{}(x); }                                                            $\C{// compiler generated desturctor call}$ \end{cfa} @VLA@ is an example of a \newterm{managed type}\footnote{A managed type affects the runtime environment versus being self-contained.} in \CFA: a type requiring a non-trivial constructor or destructor, or with a field of a managed type. A managed types is implicitly constructed upon allocation, and destructed upon deallocation to ensure proper interaction of runtime resources, in this case the @data@ array in the heap. The exact details of the placement of these implicit constructor and destructor calls are omitted here for brevity, the interested reader should consult \cite{Schluntz17}. Constructor calls are intended to seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to veteran C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes. As such, \CFA also provides syntax for \newterm{copy initialization} and \newterm{initialization parameters}: \begin{cfa} void ?{}( Array& arr, Array other ); void ?{}( Array& arr, int size, int fill ); Array y = { 20, 0xDEADBEEF }, z = y; Constructor calls seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes. As such, \CFA also provides syntax for \newterm{initialization} and \newterm{copy}: \begin{cfa} void ?{}( VLA & vla, int size, int fill );      $\C{// initialization}$ void ?{}( VLA & vla, VLA other );                       $\C{// copy}$ VLA y = { 20, 0xdeadbeef },  // initialization z = y; // copy \end{cfa} \begin{cfa} Array a, b; VLA a, b; a{};                            $\C{// default construct}$ b{ a };                         $\C{// copy construct}$ In rare situations user programmers may not wish to have constructors and destructors called; in these cases, \CFA provides an escape hatch'' to not call them. If a variable is initialized using the syntax \lstinline|S x @= {}| it will be an \newterm{unmanaged object}, and will not have constructors or destructors called. Any C initializer can be the right-hand side of an \lstinline|@=| initializer, \eg  \lstinline|Array a @= { 0, 0x0 }|, with the usual C initialization semantics. Any C initializer can be the right-hand side of an \lstinline|@=| initializer, \eg  \lstinline|VLA a @= { 0, 0x0 }|, with the usual C initialization semantics. In addition to the expressive power, \lstinline|@=| provides a simple path for migrating legacy C code to \CFA, by providing a mechanism to incrementally convert initializers; the \CFA design team decided to introduce a new syntax for this escape hatch because we believe that our RAII implementation will handle the vast majority of code in a desirable way, and we wished to maintain familiar syntax for this common case. In keeping with the general \CFA approach of adding features while respecting the C way'' of doing things, we have extended both C's polymorphic zero and typed literal syntax to interoperate with user-defined types, while maintaining a backwards-compatible semantics. \subsection{0/1} \CFA also includes a special type for @1@, @one_t@; like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code. The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where that is meaningful. \TODO{Make this sentence true} In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T& ?+=(T&, one_t)@; analogous overloads for the decrement operators are present as well. \TODO{Make this sentence true} In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@; analogous overloads for the decrement operators are present as well. \subsection{Units} The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety. C/\Celeven provide a number of complex and overlapping storage-management operation to support the following capabilities: \begin{description}[itemsep=2pt,parsep=0pt] \begin{description}[topsep=3pt,itemsep=2pt,parsep=0pt] \item[fill] after allocation the storage is filled with a specified character. ip = alloc( ip, 2 * dim ); ip = alloc( ip, 4 * dim, fill ); ip = align_alloc( 16 ); ip = align_alloc( 16, fill ); ip = align_alloc( 16, dim ); ip = align_alloc( 16, dim, fill ); \end{cfa} & ip = (int *)realloc( ip, 2 * dim * sizeof( int ) ); ip = (int *)realloc( ip, 4 * dim * sizeof( int ) ); memset( ip, fill, 4 * dim * sizeof( int ) ); \end{cfa} \end{tabular} \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} \begin{cfa} ip = align_alloc( 16 ); ip = align_alloc( 16, fill ); ip = align_alloc( 16, dim ); ip = align_alloc( 16, dim, fill ); \end{cfa} & \begin{cfa} ip = memalign( 16, sizeof( int ) ); ip = memalign( 16, sizeof( int ) ); memset( ip, fill, sizeof( int ) ); The implicit separator character (space/blank) is a separator not a terminator. The rules for implicitly adding the separator are: \begin{itemize}[itemsep=2pt,parsep=0pt] \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt] \item A separator does not appear at the start or end of a line.