Changeset 266732e for doc/theses/mike_brooks_MMath/programs
- Timestamp:
- Mar 9, 2024, 5:40:09 PM (21 months ago)
- Branches:
- master
- Children:
- b64d0f4
- Parents:
- 03606ce
- Location:
- doc/theses/mike_brooks_MMath/programs
- Files:
-
- 1 added
- 3 edited
-
bkgd-c-tyerr.c (modified) (1 diff)
-
bkgd-carray-arrty.c (modified) (2 diffs)
-
bkgd-carray-decay.c (modified) (1 diff)
-
sedcmd (added)
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/mike_brooks_MMath/programs/bkgd-c-tyerr.c
r03606ce r266732e 10 10 11 11 int main() { 12 float * x; $\C{// x points at a floating-point number}$ 13 void (*y)(void); $\C{// y points at a function}$ 14 @x = y;@ $\C{// wrong}$ 15 @y = x;@ $\C{// wrong}$ 12 16 13 /* 14 These attempts to assign @y@ to @x@ and vice-versa are obviously ill-typed. 15 */ 16 float * x; // x points at a floating-point number 17 void (*y)(void); // y points at a function 18 ERR( 19 x = y; // wrong 20 y = x; // wrong 21 ) 17 float pi = 3.14; 18 void f( void (*g)(void) ) { g(); } 19 @f( &pi );@ $\C{// wrong}$ 20 } 22 21 23 /* 24 The first gets 25 warning: assignment to `float *' from incompatible pointer type `void (*)(void)' 26 and the second gets the opposite. 27 28 Similarly, 29 */ 30 31 float pi = 3.14; 32 void f( void (*g)(void) ) { 33 g(); 34 } 35 ERR( 36 f( & pi ); // wrong 37 ) 38 /* 39 gets 40 warning: passing argument 1 of `f' from incompatible pointer type 41 with a segmentation fault at runtime. 42 43 That @f@'s attempt to call @g@ fails is not due to 3.14 being a particularly unlucky choice of value to put in the variable @pi@. 44 Rather, it is because obtaining a program that includes this essential fragment, yet exhibits a behaviour other than "doomed to crash," is a matter for an obfuscated coding competition. 45 46 A "tractable syntactic method for proving the absence of certain program behaviours 47 by classifying phrases according to the kinds of values they compute"*1 48 rejected the program. The behaviour (whose absence is unprovable) is neither minor nor unlikely. 49 The rejection shows that the program is ill-typed. 50 51 Yet, the rejection presents as a GCC warning. 52 53 In the discussion following, ``ill-typed'' means giving a nonzero @gcc -Werror@ exit condition with a message that discusses typing. 54 55 *1 TAPL-pg1 definition of a type system 56 */ 57 58 } 22 // Local Variables: // 23 // compile-command: "sed -f sedcmd bkgd-c-tyerr.c > tmp.c; gcc tmp.c" // 24 // End: // -
doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c
r03606ce r266732e 24 24 25 25 26 // SHOW(sizeof( a ), "%zd");27 // SHOW(sizeof(&a ), "%zd");28 // SHOW(sizeof( a[0]), "%zd");29 // SHOW(sizeof(&a[0]), "%zd");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 // $\rightarrow$ & pointer to array154 // & @float(*)[10]@155 // & @float (*x)[10];@156 // & @[ * [10] float ]@157 // & @[ * array(float, 10) ]@158 float (*x4)[10];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 // & pointer to array161 // & @(float*)(*)[10]@162 // & @float *(*x)[10];@163 // & @[ * [10] * float ]@164 // & @[ * array(*float, 10) ]@165 float *(*x5)[10];166 x5 = (float*(*)[10]) x4;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 // [here]170 // const114 // [here] 115 // const 171 116 172 // [later]173 // static174 // star as dimension175 // under pointer decay: int p1[const 3] being int const *p1117 // [later] 118 // static 119 // star as dimension 120 // under pointer decay: int p1[const 3] being int const *p1 176 121 177 const float * y1;178 float const * y2;179 float * const y3;122 const float * y1; 123 float const * y2; 124 float * const y3; 180 125 181 y1 = 0;182 y2 = 0;183 // y3 = 0; // bad126 y1 = 0; 127 y2 = 0; 128 // y3 = 0; // bad 184 129 185 // *y1 = 3.14; // bad186 // *y2 = 3.14; // bad187 *y3 = 3.14;130 // *y1 = 3.14; // bad 131 // *y2 = 3.14; // bad 132 *y3 = 3.14; 188 133 189 const float z1 = 1.414;190 float const z2 = 1.414;134 const float z1 = 1.414; 135 float const z2 = 1.414; 191 136 192 // z1 = 3.14; // bad193 // z2 = 3.14; // bad137 // 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: // -
doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c
r03606ce r266732e 1 1 #include <assert.h> 2 2 int main() { 3 float a[10]; $\C{// array}$ 4 float (*pa)[10] = &a; $\C{// pointer to array}$ 5 float a0 = a[0]; $\C{// element}$ 6 float *pa0 = &(a[0]); $\C{// pointer to element}$ 3 7 4 /* 5 The last section established the difference between these four types: 6 */ 8 float *pa0x = a; $\C{// (ok)}$ 9 assert( pa0 == pa0x ); 10 assert( sizeof(pa0x) != sizeof(a) ); 7 11 8 float a [10] ; // array 9 float (*pa )[10] = & a ; // pointer to array 10 float a0 = a[0] ; // element 11 float *pa0 = &(a[0]); // pointer to element 12 void f( float x[10], float *y ) { 13 static_assert( sizeof(x) == sizeof(void*) ); 14 static_assert( sizeof(y) == sizeof(void*) ); 15 } 16 f(0,0); 12 17 13 /* 14 But the expression used for obtaining the pointer to the first element is pedantic. 15 The root of all C programmer experience with arrays is the shortcut 16 */ 17 float *pa0x = a ; // (ok) 18 /* 19 which reproduces @pa0@, in type and value: 20 */ 21 assert( pa0 == pa0x ); 22 /* 23 The validity of this initialization is unsettling, in the context of the facts established in the last section. 24 Notably, it initializes name @pa0x@ from expression @a@, when they are not of the same type: 25 */ 26 assert( sizeof(pa0x) != sizeof(a) ); 18 // reusing local var `float a[10];`} 19 float v; 20 f( a, a ); $\C{// ok: two decays, one into an array spelling}$ 21 f( &v, &v ); $\C{// ok: no decays; a non-array passes to an array spelling}$ 27 22 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}$ 26 c[3] = 'p'; 27 } 28 edit(ca); $\C{// ok [decay here]}$ 29 edit(cp); $\C{// Segmentation fault}$ 30 edit("hello"); $\C{// Segmentation fault [decay here]}$ 28 31 32 void decay( float x[10] ) { 33 static_assert( sizeof(x) == sizeof(void*) ); 34 } 35 static_assert( sizeof(a) == 10 * sizeof(float) ); 36 decay(a); 29 37 38 void no_decay( float (*px)[10] ) { 39 static_assert( sizeof(*px) == 10 * sizeof(float) ); 40 } 41 static_assert( sizeof(*pa) == 10 * sizeof(float) ); 42 no_decay(pa); 43 } 30 44 31 32 33 34 35 36 37 38 39 40 void f( float x[10], float *y ) { 41 static_assert( sizeof(x) == sizeof(void*) ); 42 static_assert( sizeof(y) == sizeof(void*) ); 43 } 44 f(0,0); 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 // reusing local var `float a[10];` 61 float v; 62 f( a, a ); // ok: two decays, one into an array spelling 63 f( &v, &v ); // ok: no decays; a non-array passes to an array spelling 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 char ca[] = "hello"; // array on stack, initialized from read-only data 81 char *cp = "hello"; // pointer to read-only data [decay here] 82 void edit(char c[]) { // param is pointer 83 c[3] = 'p'; 84 } 85 edit(ca); // ok [decay here] 86 edit(cp); // Segmentation fault 87 edit("hello"); // Segmentation fault [decay here] 88 89 90 91 92 93 94 95 96 97 98 99 100 void decay( float x[10] ) { 101 static_assert( sizeof(x) == sizeof(void*) ); 102 } 103 static_assert( sizeof(a) == 10 * sizeof(float) ); 104 decay(a); 105 106 void no_decay( float (*px)[10] ) { 107 static_assert( sizeof(*px) == 10 * sizeof(float) ); 108 } 109 static_assert( sizeof(*pa) == 10 * sizeof(float) ); 110 no_decay(pa); 111 } 45 // Local Variables: // 46 // compile-command: "sed -f sedcmd bkgd-carray-decay.c > tmp.c; gcc tmp.c" // 47 // End: //
Note:
See TracChangeset
for help on using the changeset viewer.