Instructor: James Riely
$ clang -m32 typing-00.c && ./a.out
(float)*p = 2123456768.000000
*(float*)p = 96621069057346178268049192388430659584.000000
i*s = -1047484
int main() {
int *p = (int*) malloc (sizeof(int));
*p = 2123456789;
printf ("(float)*p = %f\n", (float)*p); /* loss of precision */
printf ("*(float*)p = %f\n", *(float*)p); /* rubbish */
int i = 2;
char s[] = "three";
printf ("i*s = %ld\n", i*(long)s);
}
fun f(x) { return x - 42; }
fun main() { f("dog"); }
lox11> main();
Operands must be numbers.
$ clang -m32 typing-03.c && ./a.out
f=10.000000, a[0]=10 i=10
f=10.000000, a[0]=10 i=32401
f=96621069057346178268049192388430659584.000000, a[0]=10 i=32401
int main () {
float f = 10;
int a[] = { 10 };
short i = 10;
printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
a[-1] = 2123456789; printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
a[1] = 2123456789; printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
}
$ gcc typing-06.c && ./a.out
x=2123456789, y=2123456789.000000
x=2123456789, z=38685644468023060038942720.000000
int main() {
int x = 2123456789;
double y = x;
printf ("x=%d, y=%f\n", x, y);
double *p = &x;
double z = *p;
printf ("x=%d, z=%f\n", x, z);
}
$ gcc typing-07.c && ./a.out
*fp=10.000000, *ip=1092616192
fp=0x1063010, ip=0x1063010
int main() {
int* ip = (int*) malloc (sizeof(int));
*ip = 10;
free(ip);
float* fp = (float*) malloc (sizeof(float));
*fp = 10;
printf ("*fp=%f, *ip=%d\n", *fp, *ip);
printf (" fp=%p, ip=%p\n", fp, ip);
}
$ clang -m32 typing-04.c && ./a.out
hurray!
ouch!
void unsafeCommand () { printf ("ouch!\n"); }
void safeCommand () { printf ("hurray!\n"); }
int main () {
int diff = &unsafeCommand - &safeCommand;
void (*c) () = &safeCommand;
c();
c += diff;
c();
}
$ clang -m32 typing-05.c && ./a.out
i=2123456789
f=96621069057346178268049192388430659584.000000
void floatCommand (float f) { printf ("f=%f\n", f); }
void intCommand (int i) { printf ("i=%d\n", i); }
int main () {
int diff = (void*)&intCommand - (void*)&floatCommand;
void (*c) (int) = &intCommand;
int j = 2123456789;
c(j);
c -= diff;
c(j);
}
To be safe, Java does the following
free
$ javac Typing04.java && java Typing04
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
class Typing04 {
public static void main (String[] args) {
Object[] bs = new Object[4];
Object b = bs[-1];
}
}
$ javac Typing05.java && java Typing05
Exception in thread "main" java.lang.ClassCastException: C cannot be cast to B
class A { int x; }
class B extends A { float y; }
class C extends A { char c; }
class Typing05 {
static void f (B b) {
A a = b; /* upcast always safe */
}
static void g (A a) {
B b = (B) a; /* downcast must be checked */
}
public static void main (String[] args) {
f (new B());
g (new C());
}
}
Compare with dynamic cast in C++
$ javac Typing03.java && java Typing03
Exception in thread "main" java.lang.ArrayStoreException: C
class A { int x=1; }
class B extends A { float y=2; }
class C extends A { char z='3'; }
class Typing03 {
public static void main (String[] args) {
B[] bs = new B[1];
A[] as = bs;
as[0] = new C();
B b = bs[0];
System.out.println (b.y);
}
}
This is a design flaw -- More later
null
is considered a billion dollar mistake