- Timestamp:
- Mar 9, 2024, 5:40:09 PM (2 months ago)
- Branches:
- master
- Children:
- b64d0f4
- Parents:
- 03606ce
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c
r03606ce r266732e 24 24 25 25 26 27 28 29 26 // SHOW(sizeof( a ), "%zd"); 27 // SHOW(sizeof(&a ), "%zd"); 28 // SHOW(sizeof( a[0]), "%zd"); 29 // SHOW(sizeof(&a[0]), "%zd"); 30 30 31 31 32 32 33 33 int main() { 34 float a[10]; 35 static_assert(sizeof(float) == 4); $\C{// floats (array elements) are 4 bytes}$ 36 static_assert(sizeof(void*) == 8); $\C{// pointers are 8 bytes}$ 37 static_assert(sizeof(a) == 40); $\C{// array}$ 38 static_assert(sizeof(&a) == 8 ); $\C{// pointer to array}$ 39 static_assert(sizeof(a[0]) == 4 ); $\C{// first element}$ 40 static_assert(sizeof(&(a[0])) == 8 ); $\C{// pointer to first element}$ 34 41 35 /* 36 When 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.'' 42 typeof(&a) x; $\C{// x is pointer to array}$ 43 typeof(&(a[0])) y; $\C{// y is pointer to first element}$ 44 @x = y;@ $\C{// ill-typed}$ 45 @y = x;@ $\C{// ill-typed}$ 46 static_assert(sizeof(typeof(a)) == 40); 47 static_assert(sizeof(typeof(&a)) == 8 ); 48 static_assert(sizeof(typeof(a[0])) == 4 ); 49 static_assert(sizeof(typeof(&(a[0]))) == 8 ); 37 50 38 Its qualities become apparent by inspecting the declaration 39 */ 40 float a[10]; 41 /* 51 void f( float (*pa)[10] ) { 52 static_assert(sizeof( *pa ) == 40); $\C{// array}$ 53 static_assert(sizeof( pa ) == 8 ); $\C{// pointer to array}$ 54 static_assert(sizeof( (*pa)[0] ) == 4 ); $\C{// first element}$ 55 static_assert(sizeof(&((*pa)[0])) == 8 ); $\C{// pointer to first element}$ 56 } 57 f( & a ); 42 58 43 The inspection begins by using @sizeof@ to provide definite program semantics for the intuition of an expression's type. 59 float fs[] = {3.14, 1.707}; 60 char cs[] = "hello"; 44 61 45 Assuming a target platform keeps things concrete: 46 */ 47 static_assert(sizeof(float)==4); // floats (array elements) are 4 bytes 48 static_assert(sizeof(void*)==8); // pointers are 8 bytes 49 /* 50 51 Consider the sizes of expressions derived from @a@, modified by adding ``pointer to'' and ``first element'' (and including unnecessary parentheses to avoid confusion about precedence). 52 */ 53 static_assert(sizeof( a ) == 40); // array 54 static_assert(sizeof(& a ) == 8 ); // pointer to array 55 static_assert(sizeof( a[0] ) == 4 ); // first element 56 static_assert(sizeof(&(a[0])) == 8 ); // pointer to first element 57 /* 58 That @a@ takes up 40 bytes is common reasoning for C programmers. 59 Set aside for a moment the claim that this first assertion is giving information about a type. 60 For now, note that an array and a pointer to its first element are, sometimes, different things. 61 62 The idea that there is such a thing as a pointer to an array may be surprising. 63 It is not the same thing as a pointer to the first element: 64 */ 65 typeof(& a ) x; // x is pointer to array 66 typeof(&(a[0])) y; // y is pointer to first element 67 ERR( 68 x = y; // ill-typed 69 y = x; // ill-typed 70 ) 71 /* 72 The first gets 73 warning: warning: assignment to `float (*)[10]' from incompatible pointer type `float *' 74 and the second gets the opposite. 75 */ 76 77 /* 78 We now refute a concern that @sizeof(a)@ is reporting on special knowledge from @a@ being an local variable, 79 say that it is informing about an allocation, rather than simply a type. 80 81 First, 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: 82 */ 83 static_assert(sizeof(typeof( a )) == 40); 84 static_assert(sizeof(typeof(& a )) == 8 ); 85 static_assert(sizeof(typeof( a[0] )) == 4 ); 86 static_assert(sizeof(typeof(&(a[0]))) == 8 ); 87 88 /* 89 Finally, the same sizing is reported when there is no allocation at all, and we launch the analysis instead from the pointer-to-array type. 90 */ 91 void f( float (*pa)[10] ) { 92 static_assert(sizeof( *pa ) == 40); // array 93 static_assert(sizeof( pa ) == 8 ); // pointer to array 94 static_assert(sizeof( (*pa)[0] ) == 4 ); // first element 95 static_assert(sizeof(&((*pa)[0])) == 8 ); // pointer to first element 96 } 97 f( & a ); 98 99 /* 100 So, in spite of considerable programmer success enabled by an understanding that 101 an array just a pointer to its first element (revisited TODO pointer decay), 102 this understanding is simplistic. 103 */ 104 105 /* 106 A shortened form for declaring local variables exists, provided that length information is given in the initializer: 107 */ 108 float fs[] = {3.14, 1.707}; 109 char cs[] = "hello"; 110 111 static_assert( sizeof(fs) == 2 * sizeof(float) ); 112 static_assert( sizeof(cs) == 6 * sizeof(char) ); // 5 letters + 1 null terminator 113 114 /* 115 In these declarations, the resulting types are both arrays, but their lengths are inferred. 116 */ 117 62 static_assert( sizeof(fs) == 2 * sizeof(float) ); 63 static_assert( sizeof(cs) == 6 * sizeof(char) ); $\C{// 5 letters + 1 null terminator}$ 118 64 } 119 65 66 void syntaxReferenceCheck(void) { 67 // $\rightarrow$ & (base element) 68 // & @float@ 69 // & @float x;@ 70 // & @[ float ]@ 71 // & @[ float ]@ 72 float x0; 120 73 121 void syntaxReferenceCheck(void) { 122 // $\rightarrow$ & (base element) 123 // & @float@ 124 // & @float x;@ 125 // & @[ float ]@ 126 // & @[ float ]@ 127 float x0; 74 // $\rightarrow$ & pointer 75 // & @float *@ 76 // & @float * x;@ 77 // & @[ * float ]@ 78 // & @[ * float ]@ 79 float * x1; 128 80 129 // $\rightarrow$ & pointer 130 // & @float *@131 // & @float * x;@132 // & @[ *float ]@133 // & @[ * float]@134 float * x1;81 // $\rightarrow$ & array 82 // & @float[10]@ 83 // & @float x[10];@ 84 // & @[ [10] float ]@ 85 // & @[ array(float, 10) ]@ 86 float x2[10]; 135 87 136 // $\rightarrow$ & array 137 // & @float[10]@ 138 // & @float x[10];@ 139 // & @[ [10] float ]@ 140 // & @[ array(float, 10) ]@ 141 float x2[10]; 88 typeof(float[10]) x2b; 142 89 143 typeof(float[10]) x2b; 144 145 // & array of pointers 146 // & @(float*)[10]@ 147 // & @float *x[10];@ 148 // & @[ [10] * float ]@ 149 // & @[ array(*float, 10) ]@ 150 float *x3[10]; 90 // & array of pointers 91 // & @(float*)[10]@ 92 // & @float *x[10];@ 93 // & @[ [10] * float ]@ 94 // & @[ array(*float, 10) ]@ 95 float *x3[10]; 151 96 // (float *)x3a[10]; NO 152 97 153 154 155 156 157 158 98 // $\rightarrow$ & pointer to array 99 // & @float(*)[10]@ 100 // & @float (*x)[10];@ 101 // & @[ * [10] float ]@ 102 // & @[ * array(float, 10) ]@ 103 float (*x4)[10]; 159 104 160 161 162 163 164 165 166 105 // & pointer to array 106 // & @(float*)(*)[10]@ 107 // & @float *(*x)[10];@ 108 // & @[ * [10] * float ]@ 109 // & @[ * array(*float, 10) ]@ 110 float *(*x5)[10]; 111 x5 = (float*(*)[10]) x4; 167 112 // x5 = (float(*)[10]) x4; // wrong target type; meta test suggesting above cast uses correct type 168 113 169 170 114 // [here] 115 // const 171 116 172 173 174 175 117 // [later] 118 // static 119 // star as dimension 120 // under pointer decay: int p1[const 3] being int const *p1 176 121 177 178 179 122 const float * y1; 123 float const * y2; 124 float * const y3; 180 125 181 182 183 126 y1 = 0; 127 y2 = 0; 128 // y3 = 0; // bad 184 129 185 186 187 130 // *y1 = 3.14; // bad 131 // *y2 = 3.14; // bad 132 *y3 = 3.14; 188 133 189 190 134 const float z1 = 1.414; 135 float const z2 = 1.414; 191 136 192 193 137 // z1 = 3.14; // bad 138 // z2 = 3.14; // bad 194 139 195 140 … … 199 144 void stx2() { const T x[10]; 200 145 // x[5] = 3.14; // bad 201 146 } 202 147 void stx3() { T const x[10]; 203 148 // x[5] = 3.14; // bad 204 } 149 } 150 151 // Local Variables: // 152 // compile-command: "sed -f sedcmd bkgd-carray-arrty.c > tmp.c; gcc tmp.c" // 153 // End: //
Note: See TracChangeset
for help on using the changeset viewer.