Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!ames!haven!mimsy!chris From: chris@mimsy.umd.edu (Chris Torek) Newsgroups: comp.lang.c Subject: Re: printf Message-ID: <20319@mimsy.umd.edu> Date: 21 Oct 89 14:59:30 GMT References: <543@uwm.edu> Distribution: na Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 148 In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: >I recently came across a piece of c code:(both a and b are integers) >printf("%d"+(a),b); >in passes compiler without any problem, what does this code mean ? First, learn the language definition; then apply it. This is a function call to the `printf' function; it passes two arguments. The first argument (which is not necessarily evaluated first) is "%d" + (a) which is composed of three parts. The first part is a string constant. A string constant is an anonymous array of type `array N of char', where N is the number of characters in the string, plus one for a terminating NUL character (code 0). Here "%d" becomes the triple: The third part of this expression is the sub-expression (a). In between these two parts is the `+' operator, which performs either scalar (integer or floating point) addition or pointer addition, depending on its arguments (the other two parts of the expression). These arguments are evaluated, meaning they are in `rvalue contexts'. Now we need to refer to the rule for handling array objects in rvalue contexts. The rule is: An object of type `array N of T' in an rvalue context is converted to a value of type `pointer to T' whose value is the address of the first element of that object. Thus, the value of as seen by the `+' operator is The value of `(a)' is simply the value of the variable `a', which we were told above is an `integer' (presumably an |int|, not a |long|, nor |unsigned int| nor |unsigned long| nor any variety of |short| or |char|). Hence the arguments to the `+' operator are a pointer type and an integral type, and so `+' performs pointer addition. Pointer addition is done by moving forward some number of objects, the number being determined by the integral expression and the objects being determined by the pointer expression. Here the pointer points to |char|s, and the integral expression is the value of `a'. We do not know the value of `a', so we cannot predict the result of the pointer addition. The first part of our answer, then, is that we have no idea what value is being passed to printf() as its first argument. All we know is that it has type `pointer to char'. Returning to the printf() call, the second argument is the expression `b'. This is also in an rvalue context and so its value is the value of `b'. All we know about `b' is that it is an `integer', again presumably really an |int|, not a |short| or an |unsigned long| or some other type; but we do not really know that. The second part of our answer, then, is that we have no idea what value is being passed to printf() as its second argument. All we know is that it has one of the types |int|, |long|, |unsigned int|, or |unsigned long|; probably it is |int|. Finally, we put these together with knowledge about printf(). Printf expects its first argument to have type |pointer to char| (it does) and its remaining arguments, if any, are variadic (can be any rvalue type), but must match up with types that can be derived by examining the value of the first argument. In this case, we have no idea what that value might be. All we can conclude, then, is that printf() is being called with at least one correct type, and possibly two correct types. The answer to the question: >what does this code mean ? is thus `we cannot tell'. We can, however, make a guess or two at the intended meaning. The value passed to printf must be a pointer that points to at least one character. If that character is not NUL, it must be followed by at least one more character, and so on, until we reach a character that *is* NUL. The result of "%d"+(a) will not be a valid pointer to such a sequence of characters unless (a) has one of the three values 0, 1, or 2. These value causes the pointer addition `+' operator to evaluate to and respectively. If `a' is 0, the expression reduces to printf("%d", b); which is correct (and prints to stdout the value of `b') iff `b' evaluates to an rvalue of type |int|. If `a' is 1, the expression reduces to printf("%d"+1, b); which acts like printf("d", b); which is correct regardless of the type of `b' (at least according to my draft of the proposed ANSI standard: excess arguments to printf are allowed and ignored). This prints to stdout the letter `d'. Finally, if `a' is 2, the expression reduces to printf("%d"+2, b); which acts like printf("", b); which is also always correct (as per above) and prints nothing at all. We can also conclude that if `a' has a value other than 0, 1, or 2, that the printf call is incorrect and the result is not predictable. (The result of "%d"+3 is legal but is not a pointer to one or more characters, hence the printf() can fail; and the result for other values is undefined, such pointer addition being illegal.) So our second answer to >what does this code mean ? is `either nothing at all, it being incorrect, if a is not 0, 1, or 2; or print the value of b; or print the letter d; or print nothing at all, if a is 0, 1, or 2 respectively.' Both answers depend upon some hidden assumptions, such as `the program contains the line ``#include '' before the call to printf' and `a and b have values stored in them before the call to printf'. Without more information it is impossible to verify these assumptions. There are two lessons here: If you want to know what some code means, get a good book about C and apply it. and If you want someone to explain what some code does, you must be very explicit. Saying `a and b are integers' does not provide enough information---it does not even give the actual types of a and b. -- `They were supposed to be green.' In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris