Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site utcsri.UUCP Path: utzoo!utcsri!greg From: greg@utcsri.UUCP (Gregory Smith) Newsgroups: net.lang.c Subject: Re: weird C behavior Message-ID: <2401@utcsri.UUCP> Date: Tue, 25-Mar-86 13:36:26 EST Article-I.D.: utcsri.2401 Posted: Tue Mar 25 13:36:26 1986 Date-Received: Tue, 25-Mar-86 13:49:23 EST References: <557@utastro.UUCP> <3090013@csd2.UUCP> Reply-To: greg@utcsri.UUCP (Gregory Smith) Organization: CSRI, University of Toronto Lines: 66 Keywords: printf long types Summary: Even more wrong than meets the eye In article <3090013@csd2.UUCP> dube@csd2.UUCP (Tom Dube) writes: >>Here is a short C program which gives correct output according to K & R. >>While I can't argue it's wrong, it is not transparently right, either. >>#include >>#define BIG 36864 >>int i; >>i = BIG; >>if (i != BIG) >> printf("Equality NOT found: i = %d, BIG = %d\n", i, BIG); > > Sure it's correct. i is not 36864 because it is forced into a 16 >bit integer. The numbers look the same when you print them because >you are also forcing BIG into an integer with the format %d. Try >printing both numbers with %ld. > Tom Dube Lots of people noticed that 36864 is a (long) while i is an (int). ( we must be dealing with 16-bit ints, of course ). A much more serious problem exists in the printf call, which reduces to printf("..%d..%d..", i, 36864 ); Since 36864 is a long (32 bits ) and assuming 16-bit addresses (e.g. PDP-11) the parameter list in the stack for printf looks like this: < address of string > < value of i > < low word of 36864 > < hi word of 36864 > [ Note: I am assuming that the low word of a long is stored first. ] So printf sees that two (2) integers are required (_by_looking_at_the_string_) and prints i and the lo word of the constant. You see the problem? printf("...%d...%d...%s", i, 36864, "holy lint, batman!"); The stack is now as above, with the addition of one more address at the end of the list. printf sees that two integers and one string are required, so it prints the same 2 numbers as before, and _then_tries_to_use_the_high_ _word_of_36864_as_a_string_address_! Gotcha! The arguments to printf MUST AGREE with the types specified in the format string. There is no way for printf to tell the types _or_the_data_sizes_ by looking at the stack. Thus simply changing the "%d"'s in the string to "%ld"'s, as suggested by Mr. Dube, will most probably result in strangeness. We need to convert 'i' to a long before that will work. What is needed is: printf("Equality NOT found: i = %ld, BIG = %ld\n", (long) i, (long) BIG); Now printf expects two longs, and is handed two longs. Note that the second (long) [ before BIG ] is redundant in this case, but it is what we call a Very Good Idea :-). Moral of the story: Be *sure* that the types of parameters to printf are compatible with the format specifiers given in the format string. Or: 'Caveat Printor'.( groan....). Us vaxers can be more careless because our ints and longs are both 32 bits! Note: I am 97.23% certain that LINT will not catch any error of this type. -- "No eternal reward will forgive us now for wasting the dawn" -J. Morrison ---------------------------------------------------------------------- Greg Smith University of Toronto ..!decvax!utzoo!utcsri!greg