source: doc/theses/mike_brooks_MMath/background.tex @ f5fbcad

Last change on this file since f5fbcad was f5fbcad, checked in by Peter A. Buhr <pabuhr@…>, 3 months ago

move material from background to intro

  • Property mode set to 100644
File size: 19.9 KB
Line 
1\chapter{Background}
2
3Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string,
4
5
6\section{Array}
7
8When a programmer works with an array, C semantics provide access to a type that is different in every way from ``pointer to its first element.''
9Its qualities become apparent by inspecting the declaration
10\lstinput{34-34}{bkgd-carray-arrty.c}
11The inspection begins by using @sizeof@ to provide definite program semantics for the intuition of an expression's type.
12Assuming a target platform keeps things concrete:
13\lstinput{35-36}{bkgd-carray-arrty.c}
14Consider the sizes of expressions derived from @a@, modified by adding ``pointer to'' and ``first element'' (and including unnecessary parentheses to avoid confusion about precedence).
15\lstinput{37-40}{bkgd-carray-arrty.c}
16That @a@ takes up 40 bytes is common reasoning for C programmers.
17Set aside for a moment the claim that this first assertion is giving information about a type.
18For now, note that an array and a pointer to its first element are, sometimes, different things.
19
20The idea that there is such a thing as a pointer to an array may be surprising.
21It is not the same thing as a pointer to the first element:
22\lstinput{42-45}{bkgd-carray-arrty.c}
23The first gets
24\begin{cfa}
25warning: assignment to `float (*)[10]' from incompatible pointer type `float *'
26\end{cfa}
27and the second gets the opposite.
28
29We now refute a concern that @sizeof(a)@ is reporting on special knowledge from @a@ being an local variable,
30say that it is informing about an allocation, rather than simply a type.
31
32First, recognizing that @sizeof@ has two forms, one operating on an expression, the other on a type, we observe that the original answers are unaffected by using the type-parameterized form:
33\lstinput{46-50}{bkgd-carray-arrty.c}
34Finally, the same sizing is reported when there is no allocation at all, and we launch the analysis instead from the pointer-to-array type.
35\lstinput{51-57}{bkgd-carray-arrty.c}
36So, in spite of considerable programmer success enabled by an understanding that an array just a pointer to its first element (revisited TODO pointer decay), this understanding is simplistic.
37
38A shortened form for declaring local variables exists, provided that length information is given in the initializer:
39\lstinput{59-63}{bkgd-carray-arrty.c}
40In these declarations, the resulting types are both arrays, but their lengths are inferred.
41
42\begin{tabular}{lllllll}
43@float x;@ & $\rightarrow$ & (base element) & @float@ & @float x;@ & @[ float ]@ & @[ float ]@ \\
44@float * x;@ & $\rightarrow$ & pointer & @float *@ & @float * x;@ & @[ * float ]@ & @[ * float ]@ \\
45@float x[10];@ & $\rightarrow$ & array & @float[10]@ & @float x[10];@ & @[ [10] float ]@ & @[ array(float, 10) ]@ \\
46@float *x[10];@ & $\rightarrow$ & array of pointers & @(float*)[10]@ & @float *x[10];@ & @[ [10] * float ]@ & @[ array(*float, 10) ]@ \\
47@float (*x)[10];@ & $\rightarrow$ & pointer to array & @float(*)[10]@ & @float (*x)[10];@ & @[ * [10] float ]@ & @[ * array(float, 10) ]@ \\
48@float *(*x5)[10];@ & $\rightarrow$ & pointer to array & @(float*)(*)[10]@ & @float *(*x)[10];@ & @[ * [10] * float ]@ & @[ * array(*float, 10) ]@
49\end{tabular}
50\begin{cfa}
51         x5 =    (float*(*)[10]) x4;
52//      x5 =     (float(*)[10]) x4;  // wrong target type; meta test suggesting above cast uses correct type
53
54        // [here]
55        // const
56
57        // [later]
58        // static
59        // star as dimension
60        // under pointer decay:                         int p1[const 3]  being  int const *p1
61
62        const float * y1;
63        float const * y2;
64        float * const y3;
65
66        y1 = 0;
67        y2 = 0;
68        // y3 = 0; // bad
69
70        // *y1 = 3.14; // bad
71        // *y2 = 3.14; // bad
72        *y3 = 3.14;
73
74        const float z1 = 1.414;
75        float const z2 = 1.414;
76
77        // z1 = 3.14; // bad
78        // z2 = 3.14; // bad
79
80
81}
82
83#define T float
84void stx2() { const T x[10];
85//                      x[5] = 3.14; // bad
86                        }
87void stx3() { T const x[10];
88//                      x[5] = 3.14; // bad
89                        }
90\end{cfa}
91
92My contribution is enabled by recognizing
93\begin{itemize}
94        \item There is value in using a type that knows how big the whole thing is.
95        \item The type pointer to (first) element does not.
96        \item C \emph{has} a type that knows the whole picture: array, e.g. @T[10]@.
97        \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]@.
98\end{itemize}
99
100Each of these sections, which introduces another layer of of the C arrays' story,
101concludes with an \emph{Unfortunate Syntactic Reference}.
102It shows how to spell the types under discussion,
103along with interactions with orthogonal (but easily confused) language features.
104Alterrnate spellings are listed withing a row.
105The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$.
106The 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).
107The Declaration column gives the spelling used in an object declaration, such as variable or aggregate member; parameter declarations (section TODO) follow entirely different rules.
108
109After 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!
110
111
112\CFA-specific spellings (not yet introduced) are also included here for referenceability; these can be skipped on linear reading.
113The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}.
114This fortunate syntax does not have different spellings for types vs declarations;
115a declaration is always the type followed by the declared identifier name;
116for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled:
117\begin{cfa}
118[ * [10] T ] x;
119\end{cfa}
120The \CFA-Full column gives the spelling of a different type, introduced in TODO, which has all of my contributed improvements for safety and ergonomics.
121
122\noindent
123\textbf{Unfortunate Syntactic Reference}
124
125\begin{figure}
126\centering
127\setlength{\tabcolsep}{3pt}
128\begin{tabular}{llllll}
129        & Description & Type & Declaration & \CFA-C  & \CFA-Full \\ \hline
130        $\triangleright$ & val.
131            & @T@
132            & @T x;@
133            & @[ T ]@
134            & 
135            \\ \hline
136        & \pbox{20cm}{ \vspace{2pt} val.\\ \footnotesize{no writing the val.\ in \lstinline{x}}   }\vspace{2pt}
137            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T} \\ \lstinline{T const}   }
138            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x;} \\ \lstinline{T const x;}   }
139            & @[ const T ]@
140            & 
141            \\ \hline \hline
142        $\triangleright$ & ptr.\ to val.
143            & @T *@
144            & @T * x;@
145            & @[ * T ]@
146            &
147            \\ \hline
148        & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
149            & @T * const@
150            & @T * const x;@
151            & @[ const * T ]@
152            & 
153            \\ \hline
154        & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
155            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
156            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x;} \\ \lstinline{T const * x;}   }
157            & @[ * const T ]@
158            & 
159            \\ \hline \hline
160        $\triangleright$ & ar.\ of val.
161            & @T[10]@
162            & @T x[10];@
163            & @[ [10] T ]@
164            & @[ array(T, 10) ]@
165            \\ \hline
166        & \pbox{20cm}{ \vspace{2pt} ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{x[5]}}   }\vspace{2pt}
167            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T[10]} \\ \lstinline{T const[10]}   }
168            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x[10];} \\ \lstinline{T const x[10];}   }
169            & @[ [10] const T ]@
170            & @[ const array(T, 10) ]@
171            \\ \hline
172        & ar.\ of ptr.\ to val.
173            & @T*[10]@
174            & @T *x[10];@
175            & @[ [10] * T ]@
176            & @[ array(* T, 10) ]@
177            \\ \hline
178        & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x[5]}}   }\vspace{2pt}
179            & @T * const [10]@
180            & @T * const x[10];@
181            & @[ [10] const * T ]@
182            & @[ array(const * T, 10) ]@
183            \\ \hline
184        & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*(x[5])}}   }\vspace{2pt}
185            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * [10]} \\ \lstinline{T const * [10]}   }
186            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x[10];} \\ \lstinline{T const * x[10];}   }
187            & @[ [10] * const T ]@
188            & @[ array(* const T, 10) ]@
189            \\ \hline \hline
190        $\triangleright$ & ptr.\ to ar.\ of val.
191            & @T(*)[10]@
192            & @T (*x)[10];@
193            & @[ * [10] T ]@
194            & @[ * array(T, 10) ]@
195            \\ \hline
196        & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
197            & @T(* const)[10]@
198            & @T (* const x)[10];@
199            & @[ const * [10] T ]@
200            & @[ const * array(T, 10) ]@
201            \\ \hline
202        & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{(*x)[5]}}   }\vspace{2pt}
203            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T(*)[10]} \\ \lstinline{T const (*) [10]}   }
204            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T (*x)[10];} \\ \lstinline{T const (*x)[10];}   }
205            & @[ * [10] const T ]@
206            & @[ * const array(T, 10) ]@
207            \\ \hline
208        & ptr.\ to ar.\ of ptr.\ to val.
209            & @T*(*)[10]@
210            & @T *(*x)[10];@
211            & @[ * [10] * T ]@
212            & @[ * array(* T, 10) ]@
213            \\ \hline
214\end{tabular}
215\caption{Figure}
216\end{figure}
217
218
219\subsection{Arrays decay and pointers diffract}
220
221The last section established the difference between these four types:
222\lstinput{3-6}{bkgd-carray-decay.c}
223But the expression used for obtaining the pointer to the first element is pedantic.
224The root of all C programmer experience with arrays is the shortcut
225\lstinput{8-8}{bkgd-carray-decay.c}
226which reproduces @pa0@, in type and value:
227\lstinput{9-9}{bkgd-carray-decay.c}
228The validity of this initialization is unsettling, in the context of the facts established in the last section.
229Notably, it initializes name @pa0x@ from expression @a@, when they are not of the same type:
230\lstinput{10-10}{bkgd-carray-decay.c}
231
232So, C provides an implicit conversion from @float[10]@ to @float*@, as described in ARM-6.3.2.1.3:
233\begin{quote}
234Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a
235string literal used to initialize an array
236an expression that has type ``array of type'' is
237converted to an expression with type ``pointer to type'' that points to the initial element of
238the array object
239\end{quote}
240
241This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one.
242
243It is worthy to note that the list of exception cases does not feature the occurrence of @a@ in @a[i]@.
244Thus, subscripting happens on pointers, not arrays.
245
246Subscripting proceeds first with pointer decay, if needed.  Next, ARM-6.5.2.1.2 explains that @a[i]@ is treated as if it were @(*((a)+(i)))@.
247ARM-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 @a@ is big enough and @i@ is small enough.
248Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element.
249
250Taken together, these rules also happen to illustrate that @a[i]@ and @i[a]@ mean the same thing.
251
252Subscripting a pointer when the target is standard-inappropriate is still practically well-defined.
253While the standard affords a C compiler freedom about the meaning of an out-of-bound access,
254or of subscripting a pointer that does not refer to an array element at all,
255the fact that C is famously both generally high-performance, and specifically not bound-checked,
256leads to an expectation that the runtime handling is uniform across legal and illegal accesses.
257Moreover, consider the common pattern of subscripting on a malloc result:
258\begin{cfa}
259float * fs = malloc( 10 * sizeof(float) );
260fs[5] = 3.14;
261\end{cfa}
262The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2).
263But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript.
264
265Under this assumption, a pointer being subscripted (or added to, then dereferenced)
266by any value (positive, zero, or negative), gives a view of the program's entire address space,
267centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks,
268each potentially (re)interpreted as @typeof(*p)@.
269
270I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer
271into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
272
273No pointer is exempt from array diffraction.
274
275No array shows its elements without pointer decay.
276
277A further pointer--array confusion, closely related to decay, occurs in parameter declarations.
278ARM-6.7.6.3.7 explains that when an array type is written for a parameter,
279the parameter's type becomes a type that I summarize as being the array-decayed type.
280The respective handlings of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
281\lstinput{12-16}{bkgd-carray-decay.c}
282As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variariable declaration,
283GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.''
284
285The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled:
286\lstinput{18-21}{bkgd-carray-decay.c}
287This fragment gives no warnings.
288
289The shortened parameter syntax @T x[]@ is a further way to spell ``pointer.''
290Note the opposite meaning of this spelling now, compared with its use in local variable declarations.
291This point of confusion is illustrated in:
292\lstinput{23-30}{bkgd-carray-decay.c}
293The basic two meanings, with a syntactic difference helping to distinguish,
294are illustrated in the declarations of @ca@ vs.\ @cp@,
295whose subsequent @edit@ calls behave differently.
296The syntax-caused confusion is in the comparison of the first and last lines,
297both of which use a literal to initialze an object decalared with spelling @T x[]@.
298But these initialized declarations get opposite meanings,
299depending on whether the object is a local variable or a parameter.
300
301
302In sumary, when a funciton is written with an array-typed parameter,
303\begin{itemize}
304        \item an appearance of passing an array by value is always an incorrect understanding
305        \item a dimension value, if any is present, is ignorred
306        \item pointer decay is forced at the call site and the callee sees the parameter having the decayed type
307\end{itemize}
308
309Pointer decay does not affect pointer-to-array types, because these are already pointers, not arrays.
310As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does:
311\lstinput{32-42}{bkgd-carray-decay.c}
312
313\noindent
314\textbf{Unfortunate Syntactic Reference}
315
316\noindent
317(Parameter declaration; ``no writing'' refers to the callee's ability)
318
319\begin{figure}
320\centering
321\begin{tabular}{llllll}
322        & Description & Type & Param. Decl & \CFA-C  \\ \hline
323        $\triangleright$ & ptr.\ to val.
324            & @T *@
325            & \pbox{20cm}{ \vspace{2pt} \lstinline{T * x,} \\ \lstinline{T x[10],} \\ \lstinline{T x[],}   }\vspace{2pt}
326            & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * T ]} \\ \lstinline{[ [10] T ]} \\ \lstinline{[ [] T  ]}   }
327            \\ \hline
328        & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
329            & @T * const@
330            & \pbox{20cm}{ \vspace{2pt} \lstinline{T * const x,} \\ \lstinline{T x[const 10],} \\ \lstinline{T x[const],}   }\vspace{2pt}
331            & \pbox{20cm}{ \vspace{2pt} \lstinline{[ const * T ]} \\ \lstinline{[ [const 10] T ]} \\ \lstinline{[ [const] T  ]}   }
332            \\ \hline
333        & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
334            & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
335            & \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}
336            & \pbox{20cm}{ \vspace{2pt} \lstinline{[* const T]} \\ \lstinline{[ [10] const T ]} \\ \lstinline{[ [] const T  ]}   }
337            \\ \hline \hline
338        $\triangleright$ & ptr.\ to ar.\ of val.
339            & @T(*)[10]@
340            & \pbox{20cm}{ \vspace{2pt} \lstinline{T (*x)[10],} \\ \lstinline{T x[3][10],} \\ \lstinline{T x[][10],}   }\vspace{2pt}
341            & \pbox{20cm}{ \vspace{2pt} \lstinline{[* [10] T]} \\ \lstinline{[ [3] [10] T ]} \\ \lstinline{[ [] [10] T  ]}   }
342            \\ \hline
343        & ptr.\ to ptr.\ to val.
344            & @T **@
345            & \pbox{20cm}{ \vspace{2pt} \lstinline{T ** x,} \\ \lstinline{T *x[10],} \\ \lstinline{T *x[],}   }\vspace{2pt}
346            & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * * T ]} \\ \lstinline{[ [10] * T ]} \\ \lstinline{[ [] * T  ]}   }
347            \\ \hline
348        & \pbox{20cm}{ \vspace{2pt} ptr.\ to ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{**argv}}   }\vspace{2pt}
349            & @const char **@
350            & \pbox{20cm}{ \vspace{2pt} \lstinline{const char *argv[],} \\ \footnotesize{(others elided)}   }\vspace{2pt}
351            & \pbox{20cm}{ \vspace{2pt} \lstinline{[ [] * const char ]} \\ \footnotesize{(others elided)}   }
352            \\ \hline
353\end{tabular}
354\caption{Figure}
355\end{figure}
356
357
358\subsection{Lengths may vary, checking does not}
359
360When the desired number of elements is unknown at compile time,
361a variable-length array is a solution:
362\begin{cfa}
363int main( int argc, const char *argv[] ) {
364        assert( argc == 2 );
365        size_t n = atol( argv[1] );
366        assert( 0 < n && n < 1000 );
367
368        float a[n];
369        float b[10];
370
371        // ... discussion continues here
372}
373\end{cfa}
374This arrangement allocates @n@ elements on the @main@ stack frame for @a@, just as it puts 10 elements on the @main@ stack frame for @b@.
375The variable-sized allocation of @a@ is provided by @alloca@.
376
377In 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:
378\begin{cfa}
379float *ax1 = malloc( sizeof( float[n] ) );
380float *ax2 = malloc( n * sizeof( float ) );
381float *bx1 = malloc( sizeof( float[1000000] ) );
382float *bx2 = malloc( 1000000 * sizeof( float ) );
383\end{cfa}
384
385
386VLA
387
388Parameter dependency
389
390Checking is best-effort / unsound
391
392Limited special handling to get the dimension value checked (static)
393
394
395
396\subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)}
397
398In C and \CC, ``multidimensional array'' means ``array of arrays.''  Other meanings are discussed in TODO.
399
400Just as an array's element type can be @float@, so can it be @float[10]@.
401
402While any of @float*@, @float[10]@ and @float(*)[10]@ are easy to tell apart from @float@, telling them apart from each other may need occasional reference back to TODO intro section.
403The sentence derived by wrapping each type in @-[3]@ follows.
404
405While any of @float*[3]@, @float[3][10]@ and @float(*)[3][10]@ are easy to tell apart from @float[3]@,
406telling them apart from each other is what it takes to know what ``array of arrays'' really means.
407
408Pointer decay affects the outermost array only
409
410TODO: unfortunate syntactic reference with these cases:
411
412\begin{itemize}
413        \item ar. of ar. of val (be sure about ordering of dimensions when the declaration is dropped)
414        \item ptr. to ar. of ar. of val
415\end{itemize}
416
417
418\subsection{Arrays are (but) almost values}
419
420Has size; can point to
421
422Can't cast to
423
424Can't pass as value
425
426Can initialize
427
428Can wrap in aggregate
429
430Can't assign
431
432
433\subsection{Returning an array is (but) almost possible}
434
435
436\subsection{The pointer-to-array type has been noticed before}
437
438\subsection{Multi-Dimensional}
439
440As in the last section, we inspect the declaration ...
441\lstinput{16-18}{bkgd-carray-mdim.c}
442The significant axis of deriving expressions from @a@ is now ``itself,'' ``first element'' or ``first grand-element (meaning, first element of first element).''
443\lstinput{20-44}{bkgd-carray-mdim.c}
444
445
446\section{Linked List}
447
448
449\section{String}
Note: See TracBrowser for help on using the repository browser.