Changeset b78c54f
- Timestamp:
- Apr 12, 2024, 7:49:21 AM (12 months ago)
- Branches:
- master
- Children:
- 3e1cd17, 90320ac
- Parents:
- feb999f (diff), ab780e6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 1 deleted
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified doc/theses/mike_brooks_MMath/background.tex ¶
rfeb999f rb78c54f 1 1 \chapter{Background} 2 2 3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string ,3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string. 4 4 5 5 … … 45 45 Hence, in all cases, @sizeof@ is informing about type information. 46 46 47 So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up the type system.48 This misguided analogue can be forced onto single-dimension arraysbut there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.49 50 Continuing, a short ened form for declaring local variables exists, provided that length information is given in the initializer:47 So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up by the type system. 48 This misguided analogue works for a single-dimension array but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access. 49 50 Continuing, a short form for declaring array variables exists using length information provided implicitly by an initializer. 51 51 \lstinput{59-62}{bkgd-carray-arrty.c} 52 In these declarations, the resulting types are both arrays, but their lengths are inferred. 53 54 My contribution is enabled by recognizing 52 The compiler counts the number of initializer elements and uses this value as the first dimension. 53 Unfortunately, the implicit element counting does not extend to dimensions beyond the first. 54 \lstinput{64-67}{bkgd-carray-arrty.c} 55 56 My contribution is recognizing: 55 57 \begin{itemize} 56 \item There is value in using a type that knows how big the whole thing is.58 \item There is value in using a type that knows its size. 57 59 \item The type pointer to (first) element does not. 58 60 \item C \emph{has} a type that knows the whole picture: array, e.g. @T[10]@. 59 \item This type has all the usual derived forms, which also know the whole picture. A usefully noteworthy example is pointer to array, e.g. @T(*)[10]@. 61 \item This type has all the usual derived forms, which also know the whole picture. 62 A usefully noteworthy example is pointer to array, e.g. @T (*)[10]@.\footnote{ 63 The parenthesis are necessary because subscript has higher priority than pointer in C declarations. 64 (Subscript also has higher priority than dereference in C expressions.)} 60 65 \end{itemize} 61 66 62 Each of these sections, which introduces another layer of of the C arrays' story, 63 concludes with an \emph{Unfortunate Syntactic Reference}. 64 It shows how to spell the types under discussion, 65 along with interactions with orthogonal (but easily confused) language features. 66 Alternate spellings are listed within a row. 67 68 \section{Reading Declarations} 69 70 A significant area of confusion for reading C declarations results from embedding a declared variable in a declaration, mimicking the way the variable is used in executable statements. 71 \begin{cquote} 72 \begin{tabular}{@{}ll@{}} 73 \multicolumn{1}{@{}c}{\textbf{Array}} & \multicolumn{1}{c@{}}{\textbf{Function Pointer}} \\ 74 \begin{cfa} 75 int @(*@ar@)[@5@]@; // definition 76 ... @(*@ar@)[@3@]@ += 1; // usage 77 \end{cfa} 78 & 79 \begin{cfa} 80 int @(*@f@())[@5@]@ { ... }; // definition 81 ... @(*@f@())[@3@]@ += 1; // usage 82 \end{cfa} 83 \end{tabular} 84 \end{cquote} 85 Essentially, the type is wrapped around the name in successive layers (like an \Index{onion}). 86 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise: 87 \begin{quote} 88 In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93} 89 \end{quote} 90 After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right! 91 92 \CFA provides its own type, variable and routine declarations, using a simpler syntax. 93 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type. 94 The qualifiers have the same meaning in \CFA as in C. 95 Then, a \CFA declaration is read left to right, where a function return type is enclosed in brackets @[@\,@]@. 96 \begin{cquote} 97 \begin{tabular}{@{}l@{\hspace{3em}}ll@{}} 98 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}} & \multicolumn{1}{c}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{read left to right}} \\ 99 \begin{cfa} 100 int @*@ x1 @[5]@; 101 int @(*@x2@)[5]@; 102 int @(*@f( int p )@)[5]@; 103 \end{cfa} 104 & 105 \begin{cfa} 106 @[5] *@ int x1; 107 @* [5]@ int x2; 108 @[ * [5] int ]@ f( int p ); 109 \end{cfa} 110 & 111 \begin{cfa} 112 // array of 5 pointers to int 113 // pointer to array of 5 int 114 // function returning pointer to array of 5 ints 115 \end{cfa} 116 \\ 117 & & 118 \LstCommentStyle{//\ \ \ and taking an int argument} 119 \end{tabular} 120 \end{cquote} 121 As declaration complexity increases, it becomes corresponding difficult to read and understand the C declaration form. 122 Note, writing declarations left to right is common in other programming languages, where the function return-type is often placed after the parameter declarations. 123 124 \VRef[Table]{bkgd:ar:usr:avp} introduces the many layers of the C and \CFA array story, where the \CFA story is discussion in \VRef{XXX}. 125 The \CFA-thesis column shows the new array declaration form, which is my contributed improvements for safety and ergonomics. 126 The table shows there are multiple yet equivalent forms for the array types under discussion, and subsequent discussion shows interactions with orthogonal (but easily confused) language features. 127 Each row of the table shows alternate syntactic forms. 67 128 The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$. 68 The Type column gives the spelling used in a cast or error message (though note Section TODO points out that some types cannot be casted to). 69 The Declaration column gives the spelling used in an object declaration, such as variable or aggregate member; parameter declarations (section TODO) follow entirely different rules. 70 71 After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right! 72 73 74 \CFA-specific spellings (not yet introduced) are also included here for referenceability; these can be skipped on linear reading. 75 The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}. 76 This fortunate syntax does not have different spellings for types vs declarations; 77 a declaration is always the type followed by the declared identifier name; 78 for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled: 79 \begin{cfa} 80 [ * [10] T ] x; 81 \end{cfa} 82 The \CFA-Full column gives the spelling of a different type, introduced in TODO, which has all of my contributed improvements for safety and ergonomics. 83 84 \VRef[Figure]{bkgd:ar:usr:avp} gives this reference for the discussion so far. 85 86 \begin{figure} 129 Removing the declared variable @x@, gives the type used for variable, structure field, cast or error messages \PAB{(though note Section TODO points out that some types cannot be casted to)}. 130 Unfortunately, parameter declarations \PAB{(section TODO)} have more syntactic forms and rules. 131 132 \begin{table} 87 133 \centering 88 \setlength{\tabcolsep}{3pt} 89 \begin{tabular}{llllll} 90 & Description & Type & Declaration & \CFA-C & \CFA-Full \\ \hline 91 $\triangleright$ & val. 92 & @T@ 93 & @T x;@ 94 & @[ T ]@ 95 & 96 \\ \hline 97 & \pbox{20cm}{ \vspace{2pt} val.\\ \footnotesize{no writing the val.\ in \lstinline{x}} }\vspace{2pt} 98 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T} \\ \lstinline{T const} } 99 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x;} \\ \lstinline{T const x;} } 100 & @[ const T ]@ 101 & 102 \\ \hline \hline 103 $\triangleright$ & ptr.\ to val. 104 & @T *@ 105 & @T * x;@ 106 & @[ * T ]@ 107 & 108 \\ \hline 109 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 110 & @T * const@ 111 & @T * const x;@ 112 & @[ const * T ]@ 113 & 114 \\ \hline 115 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}} }\vspace{2pt} 116 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *} } 117 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x;} \\ \lstinline{T const * x;} } 118 & @[ * const T ]@ 119 & 120 \\ \hline \hline 121 $\triangleright$ & ar.\ of val. 122 & @T[10]@ 123 & @T x[10];@ 124 & @[ [10] T ]@ 125 & @[ array(T, 10) ]@ 126 \\ \hline 127 & \pbox{20cm}{ \vspace{2pt} ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{x[5]}} }\vspace{2pt} 128 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T[10]} \\ \lstinline{T const[10]} } 129 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x[10];} \\ \lstinline{T const x[10];} } 130 & @[ [10] const T ]@ 131 & @[ const array(T, 10) ]@ 132 \\ \hline 133 & ar.\ of ptr.\ to val. 134 & @T*[10]@ 135 & @T *x[10];@ 136 & @[ [10] * T ]@ 137 & @[ array(* T, 10) ]@ 138 \\ \hline 139 & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x[5]}} }\vspace{2pt} 140 & @T * const [10]@ 141 & @T * const x[10];@ 142 & @[ [10] const * T ]@ 143 & @[ array(const * T, 10) ]@ 144 \\ \hline 145 & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*(x[5])}} }\vspace{2pt} 146 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * [10]} \\ \lstinline{T const * [10]} } 147 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x[10];} \\ \lstinline{T const * x[10];} } 148 & @[ [10] * const T ]@ 149 & @[ array(* const T, 10) ]@ 150 \\ \hline \hline 151 $\triangleright$ & ptr.\ to ar.\ of val. 152 & @T(*)[10]@ 153 & @T (*x)[10];@ 154 & @[ * [10] T ]@ 155 & @[ * array(T, 10) ]@ 156 \\ \hline 157 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 158 & @T(* const)[10]@ 159 & @T (* const x)[10];@ 160 & @[ const * [10] T ]@ 161 & @[ const * array(T, 10) ]@ 162 \\ \hline 163 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{(*x)[5]}} }\vspace{2pt} 164 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T(*)[10]} \\ \lstinline{T const (*) [10]} } 165 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T (*x)[10];} \\ \lstinline{T const (*x)[10];} } 166 & @[ * [10] const T ]@ 167 & @[ * const array(T, 10) ]@ 168 \\ \hline 169 & ptr.\ to ar.\ of ptr.\ to val. 170 & @T*(*)[10]@ 171 & @T *(*x)[10];@ 172 & @[ * [10] * T ]@ 173 & @[ * array(* T, 10) ]@ 174 \\ \hline 134 \caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.} 135 \label{bkgd:ar:usr:avp} 136 \begin{tabular}{ll|l|l|l} 137 & Description & \multicolumn{1}{c|}{C} & \multicolumn{1}{c|}{\CFA} & \multicolumn{1}{c}{\CFA-thesis} \\ 138 \hline 139 $\triangleright$ & value & @T x;@ & @T x;@ & \\ 140 \hline 141 & immutable value & @const T x;@ & @const T x;@ & \\ 142 & & @T const x;@ & @T const x;@ & \\ 143 \hline \hline 144 $\triangleright$ & pointer to value & @T * x;@ & @* T x;@ & \\ 145 \hline 146 & immutable ptr. to val. & @T * const x;@ & @const * T x;@ & \\ 147 \hline 148 & ptr. to immutable val. & @const T * x;@ & @* const T x;@ & \\ 149 & & @T const * x;@ & @* T const x;@ & \\ 150 \hline \hline 151 $\triangleright$ & array of value & @T x[10];@ & @[10] T x@ & @array(T, 10) x@ \\ 152 \hline 153 & ar.\ of immutable val. & @const T x[10];@ & @[10] const T x@ & @const array(T, 10) x@ \\ 154 & & @T const x[10];@ & @[10] T const x@ & @array(T, 10) const x@ \\ 155 \hline 156 & ar.\ of ptr.\ to value & @T * x[10];@ & @[10] * T x@ & @array(T *, 10) x@ \\ 157 & & & & @array(* T, 10) x@ \\ 158 \hline 159 & ar.\ of imm. ptr.\ to val. & @T * const x[10];@ & @[10] const * T x@ & @array(* const T, 10) x@ \\ 160 & & & & @array(const * T, 10) x@ \\ 161 \hline 162 & ar.\ of ptr.\ to imm. val. & @const T * x[10];@ & @[10] * const T x@ & @array(const T *, 10) x@ \\ 163 & & @T const * x[10];@ & @[10] * T const x@ & @array(* const T, 10) x@ \\ 164 \hline \hline 165 $\triangleright$ & ptr.\ to ar.\ of value & @T (*x)[10];@ & @* [10] T x@ & @* array(T, 10) x@ \\ 166 \hline 167 & imm. ptr.\ to ar.\ of val. & @T (* const x)[10];@ & @const * [10] T x@ & @const * array(T, 10) x@ \\ 168 \hline 169 & ptr.\ to ar.\ of imm. val. & @const T (*x)[10];@ & @* [10] const T x@ & @* const array(T, 10) x@ \\ 170 & & @T const (*x)[10];@ & @* [10] T const x@ & @* array(T, 10) const x@ \\ 171 \hline 172 & ptr.\ to ar.\ of ptr.\ to val. & @T *(*x)[10];@ & @* [10] * T x@ & @* array(T *, 10) x@ \\ 173 & & & & @* array(* T, 10) x@ \\ 174 \hline 175 175 \end{tabular} 176 \caption{Unfortunate Syntactic Reference for Array vs Pointer. Includes interaction with constness.} 177 \label{bkgd:ar:usr:avp} 178 \end{figure} 179 180 181 182 176 \end{table} 183 177 184 178 TODO: Address these parked unfortunate syntaxes … … 186 180 \item static 187 181 \item star as dimension 188 \item under pointer decay: int p1[const 3] being int const *p1182 \item under pointer decay: @int p1[const 3]@ being @int const *p1@ 189 183 \end{itemize} 190 184 … … 203 197 \lstinput{10-10}{bkgd-carray-decay.c} 204 198 205 So, C provides an implicit conversion from @float[10]@ to @float *@, as described in ARM-6.3.2.1.3:199 So, C provides an implicit conversion from @float[10]@ to @float *@. 206 200 \begin{quote} 207 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a 208 string literal used to initialize an array 209 an expression that has type ``array of type'' is 210 converted to an expression with type ``pointer to type'' that points to the initial element of 211 the array object 201 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a string literal used to 202 initialize an array an expression that has type ``array of \emph{type}'' is converted to an expression with type 203 ``pointer to \emph{type}'' that points to the initial element of the array object~\cite[\S~6.3.2.1.3]{C11} 212 204 \end{quote} 213 214 205 This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one. 215 216 206 It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@. 217 Thus, subscripting happens on pointers, not arrays. 218 219 Subscripting proceeds first with pointer decay, if needed. Next, ARM-6.5.2.1.2 explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@. 220 ARM-6.5.6.8 explains that the addition, of a pointer with an integer type, is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough. 221 Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element. 222 223 Taken together, these rules also happen to illustrate that @ar[i]@ and @i[a]@ mean the same thing. 207 Thus, subscripting happens on pointers not arrays. 208 209 Subscripting proceeds first with pointer decay, if needed. Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@. 210 \cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type, is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough. 211 Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element. 212 Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing! 224 213 225 214 Subscripting a pointer when the target is standard-inappropriate is still practically well-defined. … … 233 222 fs[5] = 3.14; 234 223 \end{cfa} 235 The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2). 236 But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript. 237 238 Under this assumption, a pointer being subscripted (or added to, then dereferenced) 239 by any value (positive, zero, or negative), gives a view of the program's entire address space, 240 centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, 241 each potentially (re)interpreted as @typeof(*p)@. 242 243 I call this phenomenon ``array diffraction,'' which is a diffraction of a single-element pointer 244 into the assumption that its target is in the middle of an array whose size is unlimited in both directions. 245 224 The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (\cite[\S~7.22.3.4.2]{C11}). 225 But \emph{nothing} more is said about this pointer value, specifically that its referent might \emph{be} an array allowing subscripting. 226 227 Under this assumption, a pointer being subscripted (or added to, then dereferenced) by any value (positive, zero, or negative), gives a view of the program's entire address space, centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, each potentially (re)interpreted as @typeof(*p)@. 228 I call this phenomenon ``array diffraction,'' which is a diffraction of a single-element pointer into the assumption that its target is in the middle of an array whose size is unlimited in both directions. 246 229 No pointer is exempt from array diffraction. 247 248 230 No array shows its elements without pointer decay. 249 231 250 232 A further pointer--array confusion, closely related to decay, occurs in parameter declarations. 251 ARM-6.7.6.3.7explains that when an array type is written for a parameter,252 the parameter's type becomes a type that I summarize as beingthe array-decayed type.253 The respective handling sof the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.233 \cite[\S~6.7.6.3.7]{C11} explains that when an array type is written for a parameter, 234 the parameter's type becomes a type that can be summarized as the array-decayed type. 235 The respective handling of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer. 254 236 \lstinput{12-16}{bkgd-carray-decay.c} 255 237 As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration, 256 GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.'' 257 258 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled: 238 @gcc@ also gives this code the warning for the first assertion: 239 \begin{cfa} 240 warning: 'sizeof' on array function parameter 'x' will return size of 'float *' 241 \end{cfa} 242 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it is spelled: 259 243 \lstinput{18-21}{bkgd-carray-decay.c} 260 244 This fragment gives no warnings. … … 272 256 depending on whether the object is a local variable or a parameter. 273 257 274 275 258 In summary, when a function is written with an array-typed parameter, 276 259 \begin{itemize} … … 283 266 As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does: 284 267 \lstinput{32-42}{bkgd-carray-decay.c} 285 286 \VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations. 287 288 \begin{figure} 268 \VRef[Table]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter declarations. 269 270 \begin{table} 271 \caption{Syntactic Reference for Decay during Parameter-Passing. 272 Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.} 273 \label{bkgd:ar:usr:decay-parm} 289 274 \centering 290 275 \begin{tabular}{llllll} 291 & Description & Type & Param. Decl & \CFA-C \\ \hline 292 $\triangleright$ & ptr.\ to val. 293 & @T *@ 294 & \pbox{20cm}{ \vspace{2pt} \lstinline{T * x,} \\ \lstinline{T x[10],} \\ \lstinline{T x[],} }\vspace{2pt} 295 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * T ]} \\ \lstinline{[ [10] T ]} \\ \lstinline{[ [] T ]} } 296 \\ \hline 297 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 298 & @T * const@ 299 & \pbox{20cm}{ \vspace{2pt} \lstinline{T * const x,} \\ \lstinline{T x[const 10],} \\ \lstinline{T x[const],} }\vspace{2pt} 300 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ const * T ]} \\ \lstinline{[ [const 10] T ]} \\ \lstinline{[ [const] T ]} } 301 \\ \hline 302 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}} }\vspace{2pt} 303 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *} } 304 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x,} \\ \lstinline{T const * x,} \\ \lstinline{const T x[10],} \\ \lstinline{T const x[10],} \\ \lstinline{const T x[],} \\ \lstinline{T const x[],} }\vspace{2pt} 305 & \pbox{20cm}{ \vspace{2pt} \lstinline{[* const T]} \\ \lstinline{[ [10] const T ]} \\ \lstinline{[ [] const T ]} } 306 \\ \hline \hline 307 $\triangleright$ & ptr.\ to ar.\ of val. 308 & @T(*)[10]@ 309 & \pbox{20cm}{ \vspace{2pt} \lstinline{T (*x)[10],} \\ \lstinline{T x[3][10],} \\ \lstinline{T x[][10],} }\vspace{2pt} 310 & \pbox{20cm}{ \vspace{2pt} \lstinline{[* [10] T]} \\ \lstinline{[ [3] [10] T ]} \\ \lstinline{[ [] [10] T ]} } 311 \\ \hline 312 & ptr.\ to ptr.\ to val. 313 & @T **@ 314 & \pbox{20cm}{ \vspace{2pt} \lstinline{T ** x,} \\ \lstinline{T *x[10],} \\ \lstinline{T *x[],} }\vspace{2pt} 315 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * * T ]} \\ \lstinline{[ [10] * T ]} \\ \lstinline{[ [] * T ]} } 316 \\ \hline 317 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{**argv}} }\vspace{2pt} 318 & @const char **@ 319 & \pbox{20cm}{ \vspace{2pt} \lstinline{const char *argv[],} \\ \footnotesize{(others elided)} }\vspace{2pt} 320 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ [] * const char ]} \\ \footnotesize{(others elided)} } 321 \\ \hline 276 & Description & Type & Parameter Declaration & \CFA \\ 277 \hline 278 & & & @T * x,@ & @* T x,@ \\ 279 $\triangleright$ & pointer to value & @T *@ & @T x[10],@ & @[10] T x,@ \\ 280 & & & @T x[],@ & @[] T x,@ \\ 281 \hline 282 & & & @T * const x,@ & @const * T x@ \\ 283 & immutable ptr.\ to val. & @T * const@ & @T x[const 10],@ & @[const 10] T x,@ \\ 284 & & & @T x[const],@ & @[const] T x,@\\ 285 \hline 286 & & & @const T * x,@ & @ * const T x,@ \\ 287 & & & @T const * x,@ & @ * T const x,@ \\ 288 & ptr.\ to immutable val. & @const T *@ & @const T x[10],@ & @[10] const T x,@ \\ 289 & & @T const *@ & @T const x[10],@ & @[10] T const x,@ \\ 290 & & & @const T x[],@ & @[] const T x,@ \\ 291 & & & @T const x[],@ & @[] T const x,@ \\ 292 \hline \hline 293 & & & @T (*x)[10],@ & @* [10] T x,@ \\ 294 $\triangleright$ & ptr.\ to ar.\ of val. & @T(*)[10]@ & @T x[3][10],@ & @[3][10] T x,@ \\ 295 & & & @T x[][10],@ & @[][10] T x,@ \\ 296 \hline 297 & & & @T ** x,@ & @** T x,@ \\ 298 & ptr.\ to ptr.\ to val. & @T **@ & @T * x[10],@ & @[10] * T x,@ \\ 299 & & & @T * x[],@ & @[] * T x,@ \\ 300 \hline 301 & ptr.\ to ptr.\ to imm.\ val. & @const char **@ & @const char * argv[],@ & @[] * const char argv,@ \\ 302 & & & \emph{others elided} & \emph{others elided} \\ 303 \hline 322 304 \end{tabular} 323 \caption{Unfortunate Syntactic Reference for Decay during Parameter-Passing. Includes interaction with constness, where ``no writing'' refers to a restriction on the callee's ability.} 324 \label{bkgd:ar:usr:decay-parm} 325 \end{figure} 305 \end{table} 326 306 327 307 328 308 \subsection{Lengths may vary, checking does not} 329 309 330 When the desired number of elements is unknown at compile time, 331 a variable-length array is a solution: 332 \begin{cfa} 333 int main( int argc, const char *argv[] ) { 310 When the desired number of elements is unknown at compile time, a variable-length array is a solution: 311 \begin{cfa} 312 int main( int argc, const char * argv[] ) { 334 313 assert( argc == 2 ); 335 314 size_t n = atol( argv[1] ); 336 assert( 0 < n && n < 1000 ); 337 315 assert( 0 < n ); 338 316 float ar[n]; 339 317 float b[10]; 340 341 318 // ... discussion continues here 342 319 } 343 320 \end{cfa} 344 This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, just as it puts 10 elements on the @main@ stack frame for @b@. 345 The variable-sized allocation of @ar@ is provided by @alloca@. 346 347 In a situation where the array sizes are not known to be small enough for stack allocation to be sensible, corresponding heap allocations are achievable as: 348 \begin{cfa} 349 float *ax1 = malloc( sizeof( float[n] ) ); 350 float *ax2 = malloc( n * sizeof( float ) ); 351 float *bx1 = malloc( sizeof( float[1000000] ) ); 352 float *bx2 = malloc( 1000000 * sizeof( float ) ); 353 \end{cfa} 354 355 356 VLA 321 This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, called a \newterm{variable length array} (VLA), as well as 10 elements in the same stack frame for @b@. 322 The variable-sized allocation of @ar@ is provided by the @alloca@ routine, which bumps the stack pointer. 323 Note, the C standard supports VLAs~\cite[\S~6.7.6.2.4]{C11} as a conditional feature, but the \CC standard does not; 324 both @gcc@ and @g++@ support VLAs. 325 As well, there is misinformation about VLAs, \eg VLAs cause stack failures or are inefficient. 326 VLAs exist as far back as Algol W~\cite[\S~5.2]{AlgolW} and are a sound and efficient data type. 327 328 For high-performance applications, the stack size can be fixed and small (coroutines or user-level threads). 329 Here, VLAs can overflow the stack, so a heap allocation is used. 330 \begin{cfa} 331 float * ax1 = malloc( sizeof( float[n] ) ); 332 float * ax2 = malloc( n * sizeof( float ) ); 333 float * bx1 = malloc( sizeof( float[1000000] ) ); 334 float * bx2 = malloc( 1000000 * sizeof( float ) ); 335 \end{cfa} 357 336 358 337 Parameter dependency … … 363 342 364 343 365 366 \subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)} 344 \subsection{Dynamically sized, multidimensional arrays} 367 345 368 346 In C and \CC, ``multidimensional array'' means ``array of arrays.'' Other meanings are discussed in TODO. … … 416 394 \section{Linked List} 417 395 396 Linked-lists are blocks of storage connected using one or more pointers. 397 The storage block is logically divided into data and links (pointers), where the links are the only component used by the list structure. 398 Since the data is opaque, list structures are often polymorphic over the data, which is normally homogeneous. 399 418 400 419 401 \section{String} 402 403 A string is a logical sequence of symbols, where the form of the symbols can vary significantly: 7/8-bit characters (ASCII/Latin-1), or 2/4/8-byte (UNICODE) characters/symbols or variable length (UTF-8/16/32) characters. 404 A string can be read left-to-right, right-to-left, top-to-bottom, and have stacked elements (Arabic). 405 406 An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in @'x'@. 407 A wide character constant is the same, except prefixed by the letter @L@, @u@, or @U@. 408 With a few exceptions detailed later, the elements of the sequence are any members of the source character set; 409 they are mapped in an implementation-defined manner to members of the execution character set. 410 411 A C character-string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in @"xyz"@. 412 A UTF-8 string literal is the same, except prefixed by @u8@. 413 A wide string literal is the same, except prefixed by the letter @L@, @u@, or @U@. 414 415 For UTF-8 string literals, the array elements have type @char@, and are initialized with the characters of the multibyte character sequence, as encoded in UTF-8. 416 For wide string literals prefixed by the letter @L@, the array elements have type @wchar_t@ and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by the @mbstowcs@ function with an implementation-defined current locale. 417 For wide string literals prefixed by the letter @u@ or @U@, the array elements have type @char16_t@ or @char32_t@, respectively, and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by successive calls to the @mbrtoc16@, or @mbrtoc32@ function as appropriate for its type, with an implementation-defined current locale. 418 The value of a string literal containing a multibyte character or escape sequence not represented in the executioncharacter set is implementation-defined. 419 420 421 Another bad C design decision is to have null-terminated strings rather than maintaining a separate string length. 422 \begin{quote} 423 Technically, a string is an array whose elements are single characters. 424 The compiler automatically places the null character @\0@ at the end of each such string, so programs can conveniently find the end. 425 This representation means that there is no real limit to how long a string can be, but programs have to scan one completely to determine its length. 426 \end{quote} -
TabularUnified doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c ¶
rfeb999f rb78c54f 57 57 f( &ar ); 58 58 59 float fs[] = {3.14, 1.7 07};59 float fs[] = {3.14, 1.77}; 60 60 char cs[] = "hello"; 61 61 static_assert( sizeof(fs) == 2 * sizeof(float) ); 62 62 static_assert( sizeof(cs) == 6 * sizeof(char) ); $\C{// 5 letters + 1 null terminator}$ 63 63 64 float fm[][2] = { {3.14, 1.77}, {12.4, 0.01}, {7.8, 1.23} }; $\C{// brackets define structuring}$ 65 char cm[][sizeof("hello")] = { "hello", "hello", "hello" }; 66 static_assert( sizeof(fm) == 3 * 2 * sizeof(float) ); 67 static_assert( sizeof(cm) == 3 * 6 * sizeof(char) ); 64 68 } 65 69 -
TabularUnified doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c ¶
rfeb999f rb78c54f 4 4 float (*pa)[10] = &a; $\C{// pointer to array}$ 5 5 float a0 = a[0]; $\C{// element}$ 6 float * pa0 = &(a[0]); $\C{// pointer to element}$6 float * pa0 = &(a[0]); $\C{// pointer to element}$ 7 7 8 float * pa0x = a; $\C{// (ok)}$8 float * pa0x = a; $\C{// (ok)}$ 9 9 assert( pa0 == pa0x ); 10 10 assert( sizeof(pa0x) != sizeof(a) ); 11 11 12 void f( float x[10], float * y ) {13 static_assert( sizeof(x) == sizeof(void *) );14 static_assert( sizeof(y) == sizeof(void *) );12 void f( float x[10], float * y ) { 13 static_assert( sizeof(x) == sizeof(void *) ); 14 static_assert( sizeof(y) == sizeof(void *) ); 15 15 } 16 16 f(0,0); … … 22 22 23 23 char ca[] = "hello"; $\C{// array on stack, initialized from read-only data}$ 24 char * cp = "hello";$\C{// pointer to read-only data [decay here]}$25 void edit( char c[] ) { $\C{// param is pointer}$24 char * cp = "hello"; $\C{// pointer to read-only data [decay here]}$ 25 void edit( char c[] ) { $\C{// parameter is pointer}$ 26 26 c[3] = 'p'; 27 27 } 28 28 edit( ca ); $\C{// ok [decay here]}$ 29 edit( c p );$\C{// Segmentation fault}$29 edit( cp ); $\C{// Segmentation fault}$ 30 30 edit( "hello" ); $\C{// Segmentation fault [decay here]}$ 31 31 32 32 void decay( float x[10] ) { 33 static_assert( sizeof(x) == sizeof(void *) );33 static_assert( sizeof(x) == sizeof(void *) ); 34 34 } 35 35 static_assert( sizeof(a) == 10 * sizeof(float) ); -
TabularUnified src/AST/Pass.proto.hpp ¶
rfeb999f rb78c54f 226 226 // Now the original containers should still have the unchanged values 227 227 // but also contain the new values. 228 }229 };230 231 /// Used by previsit implementation232 /// We need to reassign the result to 'node', unless the function233 /// returns void, then we just leave 'node' unchanged234 template<bool is_void>235 struct __assign;236 237 template<>238 struct __assign<true> {239 template<typename core_t, typename node_t>240 static inline void result( core_t & core, const node_t * & node ) {241 core.previsit( node );242 }243 };244 245 template<>246 struct __assign<false> {247 template<typename core_t, typename node_t>248 static inline void result( core_t & core, const node_t * & node ) {249 node = core.previsit( node );250 assertf(node, "Previsit must not return NULL");251 }252 };253 254 /// Used by postvisit implementation255 /// We need to return the result unless the function256 /// returns void, then we just return the original node257 template<bool is_void>258 struct __return;259 260 template<>261 struct __return<true> {262 template<typename core_t, typename node_t>263 static inline const node_t * result( core_t & core, const node_t * & node ) {264 core.postvisit( node );265 return node;266 }267 };268 269 template<>270 struct __return<false> {271 template<typename core_t, typename node_t>272 static inline auto result( core_t & core, const node_t * & node ) {273 return core.postvisit( node );274 228 } 275 229 }; … … 297 251 ); 298 252 299 __assign< 300 std::is_void< 301 decltype( core.previsit( node ) ) 302 >::value 303 >::result( core, node ); 253 // We need to reassign the result to 'node', unless the function 254 // returns void, then we just leave 'node' unchanged 255 if constexpr ( std::is_void_v<decltype( core.previsit( node ) )> ) { 256 core.previsit( node ); 257 } else { 258 node = core.previsit( node ); 259 assertf(node, "Previsit must not return NULL"); 260 } 304 261 } 305 262 … … 312 269 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 313 270 { 314 return __return< 315 std::is_void< 316 decltype( core.postvisit( node ) ) 317 >::value 318 >::result( core, node ); 271 // We need to return the result unless the function 272 // returns void, then we just return the original node 273 if constexpr ( std::is_void_v<decltype( core.postvisit( node ) )> ) { 274 core.postvisit( node ); 275 return node; 276 } else { 277 return core.postvisit( node ); 278 } 319 279 } 320 280 -
TabularUnified src/Parser/StatementNode.cc ¶
rfeb999f rb78c54f 122 122 ast::Expr * cond = nullptr; 123 123 if ( ctl->condition ) { 124 // compare the provided condition against 0 125 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) ); 124 cond = maybeMoveBuild( ctl->condition ); 126 125 } else { 127 126 for ( ast::ptr<ast::Stmt> & stmt : inits ) { … … 129 128 auto declStmt = stmt.strict_as<ast::DeclStmt>(); 130 129 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>(); 131 ast::Expr * nze = n otZeroExpr( new ast::VariableExpr( dwt->location, dwt ));130 ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt ); 132 131 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze; 133 132 } … … 200 199 // do-while cannot have declarations in the contitional, so init is always empty 201 200 return new ast::WhileDoStmt( location, 202 notZeroExpr( maybeMoveBuild( ctl )),201 maybeMoveBuild( ctl ), 203 202 buildMoveSingle( stmt ), 204 203 buildMoveOptional( else_ ), … … 213 212 214 213 ast::Expr * astcond = nullptr; // maybe empty 215 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ));214 astcond = maybeMoveBuild( forctl->condition ); 216 215 217 216 ast::Expr * astincr = nullptr; // maybe empty … … 330 329 clause->target = maybeBuild( targetExpr ); 331 330 clause->stmt = maybeMoveBuild( stmt ); 332 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));331 clause->when_cond = maybeMoveBuild( when ); 333 332 334 333 ExpressionNode * next = targetExpr->next; … … 345 344 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) { 346 345 existing->else_stmt = maybeMoveBuild( stmt ); 347 existing->else_cond = notZeroExpr( maybeMoveBuild( when ));346 existing->else_cond = maybeMoveBuild( when ); 348 347 349 348 (void)location; … … 354 353 existing->timeout_time = maybeMoveBuild( timeout ); 355 354 existing->timeout_stmt = maybeMoveBuild( stmt ); 356 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ));355 existing->timeout_cond = maybeMoveBuild( when ); 357 356 358 357 (void)location; … … 362 361 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 363 362 ast::WhenClause * clause = new ast::WhenClause( loc ); 364 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));363 clause->when_cond = maybeMoveBuild( when ); 365 364 clause->stmt = maybeMoveBuild( stmt ); 366 365 clause->target = maybeMoveBuild( targetExpr ); … … 369 368 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) { 370 369 ast::WhenClause * clause = new ast::WhenClause( loc ); 371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));370 clause->when_cond = maybeMoveBuild( when ); 372 371 clause->stmt = maybeMoveBuild( stmt ); 373 372 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); … … 508 507 509 508 ast::Expr * astcond = nullptr; // maybe empty 510 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ));509 astcond = maybeMoveBuild( forctl->condition ); 511 510 512 511 ast::Expr * astincr = nullptr; // maybe empty -
TabularUnified src/Parser/module.mk ¶
rfeb999f rb78c54f 31 31 Parser/parser.yy \ 32 32 Parser/ParserTypes.h \ 33 Parser/parserutility.cc \34 33 Parser/parserutility.h \ 35 34 Parser/RunParser.cpp \ -
TabularUnified src/Parser/parserutility.h ¶
rfeb999f rb78c54f 17 17 18 18 #include "AST/Copy.hpp" // for shallowCopy 19 namespace ast {20 class Expr;21 }22 23 ast::Expr * notZeroExpr( const ast::Expr *orig );24 19 25 20 template< typename T > -
TabularUnified src/ResolvExpr/CandidateFinder.cpp ¶
rfeb999f rb78c54f 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr49 48 #include "SymTab/Mangler.h" 50 49 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1587 1586 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1588 1587 CandidateFinder finder1( context, tenv ); 1589 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );1588 ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 ); 1590 1589 finder1.find( arg1, ResolveMode::withAdjustment() ); 1591 1590 if ( finder1.candidates.empty() ) return; 1592 1591 1593 1592 CandidateFinder finder2( context, tenv ); 1594 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );1593 ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 ); 1595 1594 finder2.find( arg2, ResolveMode::withAdjustment() ); 1596 1595 if ( finder2.candidates.empty() ) return; … … 1618 1617 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1619 1618 // candidates for condition 1620 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );1619 ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 ); 1621 1620 CandidateFinder finder1( context, tenv ); 1622 1621 finder1.find( arg1, ResolveMode::withAdjustment() ); … … 2201 2200 } 2202 2201 2202 const ast::Expr * createCondExpr( const ast::Expr * expr ) { 2203 assert( expr ); 2204 return new ast::CastExpr( expr->location, 2205 ast::UntypedExpr::createCall( expr->location, 2206 "?!=?", 2207 { 2208 expr, 2209 new ast::ConstantExpr( expr->location, 2210 new ast::ZeroType(), "0", std::make_optional( 0ull ) 2211 ), 2212 } 2213 ), 2214 new ast::BasicType( ast::BasicType::SignedInt ) 2215 ); 2216 } 2217 2203 2218 } // namespace ResolvExpr 2204 2219 -
TabularUnified src/ResolvExpr/CandidateFinder.hpp ¶
rfeb999f rb78c54f 70 70 const ast::Expr * expr, Cost & cost ); 71 71 72 /// Wrap an expression to convert the result to a conditional result. 73 const ast::Expr * createCondExpr( const ast::Expr * expr ); 74 72 75 } // namespace ResolvExpr 73 76 -
TabularUnified src/ResolvExpr/Resolver.cc ¶
rfeb999f rb78c54f 340 340 } 341 341 342 ast::ptr< ast::Expr > findCondExpression( 343 const ast::Expr * untyped, const ResolveContext & context 344 ) { 345 if ( nullptr == untyped ) return untyped; 346 ast::ptr<ast::Expr> condExpr = createCondExpr( untyped ); 347 return findIntegralExpression( condExpr, context ); 348 } 349 342 350 /// check if a type is a character type 343 351 bool isCharType( const ast::Type * t ) { … … 356 364 return it != end; 357 365 } 358 } 366 } // anonymous namespace 359 367 360 368 class Resolver final … … 729 737 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) { 730 738 return ast::mutate_field( 731 ifStmt, &ast::IfStmt::cond, find IntegralExpression( ifStmt->cond, context ) );739 ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) ); 732 740 } 733 741 734 742 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) { 735 743 return ast::mutate_field( 736 whileDoStmt, &ast::WhileDoStmt::cond, find IntegralExpression( whileDoStmt->cond, context ) );744 whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) ); 737 745 } 738 746 … … 740 748 if ( forStmt->cond ) { 741 749 forStmt = ast::mutate_field( 742 forStmt, &ast::ForStmt::cond, find IntegralExpression( forStmt->cond, context ) );750 forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) ); 743 751 } 744 752 … … 1075 1083 1076 1084 // Resolve the conditions as if it were an IfStmt, statements normally 1077 clause2->when_cond = find SingleExpression( clause.when_cond, context );1085 clause2->when_cond = findCondExpression( clause.when_cond, context ); 1078 1086 clause2->stmt = clause.stmt->accept( *visitor ); 1079 1087 … … 1089 1097 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt }; 1090 1098 auto timeout_time = findSingleExpression( stmt->timeout_time, target, context ); 1091 auto timeout_cond = find SingleExpression( stmt->timeout_cond, context );1099 auto timeout_cond = findCondExpression( stmt->timeout_cond, context ); 1092 1100 auto timeout_stmt = stmt->timeout_stmt->accept( *visitor ); 1093 1101 … … 1102 1110 if ( stmt->else_stmt ) { 1103 1111 // resolve the condition like IfStmt, stmts normally 1104 auto else_cond = find SingleExpression( stmt->else_cond, context );1112 auto else_cond = findCondExpression( stmt->else_cond, context ); 1105 1113 auto else_stmt = stmt->else_stmt->accept( *visitor ); 1106 1114
Note: See TracChangeset
for help on using the changeset viewer.