448,563 Members | 1,241 Online
Need help? Post your question and get tips & solutions from a community of 448,563 IT Pros & Developers. It's quick & easy.

# Associativity of unary C Operators

 P: n/a I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in increment". int i = 10; ~!*&i++; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in unary "&"". int *p; ~!-&*p--; It doesn't compile, why? The problem seems to be the -, the compiler says: "Error: invalid type of argument to unary minus". I guess the problem is that you can't do unary minus on pointers, and it doesn't make sense to do so either. The following does compile on the other hand: int *p; p = (int *) = 0x10101010; /*Just to set it to some value..*/ ~!&*p--; p results in having the value 0x1010100c which I understand why. Is it possible to make an expression with all the unary operators one after another? In general, is it good programming practice to make use of the precedence and associativity of operators? Using precedence/associativity of operators when combining the operators (probably) reduces the number of codelines (compared to "spelling it out"), but doesn't it make the source code more difficult to read? Isn't it better to instead "spell it out"? Another question, when would you use the unary operator sizeof with other unary operators? To save code lines? Quite a few questions, hmm, hope someone will be able to respond..! BR! Jan 1 '07 #1
28 Replies

 P: n/a dspfun said: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? Because ++ only works on objects, and the result of p-- is an expression, but not an object. Other problems: p has no value, so p-- invokes undefined behaviour. It points nowhere in particular, so even if ++p-- were meaningful (which it is not), *++p-- would be dereferencing an indeterminate pointer value - undefined behaviour again. int i = 10; ~!*&i++; It doesn't compile, why? Because & only works on objects, and the result of p-- is an expression, but not an object. int *p; ~!-&*p--; It doesn't compile, why? Because unary minus only works on arithmetic types, and int * is not an arithmetic type. The following does compile on the other hand: int *p; p = (int *) = 0x10101010; /*Just to set it to some value..*/ No, it doesn't. Drop the second =. ~!&*p--; p results in having the value 0x1010100c which I understand why. The behaviour is undefined because p's value is changed to an invalid value. Is it possible to make an expression with all the unary operators one after another? Probably not. What possible point could there be to it? In general, is it good programming practice to make use of the precedence and associativity of operators? It is good programming practice to be aware of the precedence and associativity characteristics of C, but to make a maintenance programmer's job easier it is generally best to use parentheses rather than insist on the maintainer knowing K&R2 p53 off by heart. It is, however, generally considered necessary for all C programmers to be aware that multiplication and division take precedence over addition and subtraction, however, so there is no need to parenthesise the multiplication in v = a + b * c + d. Using precedence/associativity of operators when combining the operators (probably) reduces the number of codelines (compared to "spelling it out"), but doesn't it make the source code more difficult to read? Yes. Isn't it better to instead "spell it out"? Yes. Another question, when would you use the unary operator sizeof with other unary operators? To save code lines? No. I don't generally think of "when would I use such-and-such an operator with such-and-such another operator?". Each operator is a tool. I know when I'd use a saw, and I know when I'd use a screwdriver, but the question "when would I use a screwdriver with a saw?" doesn't really mean a lot. Saving code lines as an end in itself is only ever a goal in IOCCC. Write for clarity, not brevity. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 1 '07 #2

 P: n/a "dspfun"

 P: n/a dspfun wrote: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in increment". Applying ++ to p-- is applying it to a value, not an object, but the ++ operator has a side effect which makes sense only when applied to a modifiable object. > int i = 10; ~!*&i++; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in unary "&"". i++ is not an object: it has no address for the & operator to return. [etc] In general, is it good programming practice to make use of the precedence and associativity of operators? It is good programming practice to use operators only in contexts for which they make sense. Why are writing arcane expressions like these when you don't have a clue what the operators do? Jan 2 '07 #4

 P: n/a Thanks for your repsonse! However, I'm not sure I follow what you mean, please see below. Richard Heathfield skrev: dspfun said: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? Because ++ only works on objects, and the result of p-- is an expression, but not an object. Other problems: p has no value, so p-- invokes undefined behaviour. It points nowhere in particular, so even if ++p-- were meaningful (which it is not), *++p-- would be dereferencing an indeterminate pointer value - undefined behaviour again. Expression = An expression in C is any valid combination of operators, constants and variables. As I understand your reasoning it's not possible to have multiple operators in the same expression, but that is not true. Or am I misunderstanding you? Why does dereferencing p-- work, e.g. *p-- works. But ++p-- doesn't work. You say that ++ only works on objects, what is your definition of an object C. int i = 10; ~!*&i++; It doesn't compile, why? Because & only works on objects, and the result of p-- is an expression, but not an object. Not sure I understan what you mean. What is your definition of an object in C? > int *p; ~!-&*p--; It doesn't compile, why? Because unary minus only works on arithmetic types, and int * is not an arithmetic type. Yes, thank you! Jan 2 '07 #5

 P: n/a dspfun said: Richard Heathfield skrev: >dspfun said: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? Because ++ only works on objects, and the result of p-- is an expression,but not an object. Other problems: p has no value, so p-- invokesundefined behaviour. It points nowhere in particular, so even if ++p--were meaningful (which it is not), *++p-- would be dereferencing anindeterminate pointer value - undefined behaviour again. Expression = An expression in C is any valid combination of operators, constants and variables. "An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof." As I understand your reasoning it's not possible to have multiple operators in the same expression, but that is not true. Or am I misunderstanding you? b + c * d is a legal expression with two operators, so you are misunderstanding me. > Why does dereferencing p-- work, e.g. *p-- works. But ++p-- doesn't work. Because ++ takes as its operand an object with scalar type. The expression p-- yields a value, not an object. You say that ++ only works on objects, what is your definition of an object C. I don't have one, but the C Standard says: * Object --- a region of data storage in the execution environment, the contents of which can represent values. Except for bit-fields, objects are composed of contiguous sequences of one or more bytes, the number, order, and encoding of which are either explicitly specified or implementation-defined. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 2 '07 #6

 P: n/a Martin Ambuhl skrev: dspfun wrote: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in increment". Applying ++ to p-- is applying it to a value, not an object, but the ++ operator has a side effect which makes sense only when applied to a modifiable object. p-- is an expression. It is possible to do *p--. So we can use at least some operators on expressions, that's probably why we have the associativity rules. I'm having problem understanding what you mean, probably because I don't understand your definition of object and value? In C I know of different types of variables, constants, pointers, arrays and structs as well as enums. int i = 10; ~!*&i++; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in unary "&"". i++ is not an object: it has no address for the & operator to return. Same question as above, what is the defintion of an object? [etc] In general, is it good programming practice to make use of the precedence and associativity of operators? It is good programming practice to use operators only in contexts for which they make sense. Why are writing arcane expressions like these when you don't have a clue what the operators do? That's the reason why I'm writing arcane expressions like this; to grasp a solid understanding of what the operators are doing to its operands and how the operators can be used. Thanks for your response!! Jan 2 '07 #7

 P: n/a Why does dereferencing p-- work, e.g. *p-- works. But ++p-- doesn't work. Because ++ takes as its operand an object with scalar type. The expression p-- yields a value, not an object. So why does it work when you split ++p-- in two different lines?: p--; ++p; You'll probably say the same thing again, but what is the main difference when splitting the expression in two? Thanks again for your response!! Jan 2 '07 #8

 P: n/a dspfun wrote: Martin Ambuhl skrev: dspfun wrote: I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. > int *p; ~!&*++p--; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in increment". Applying ++ to p-- is applying it to a value, not an object, but the ++ operator has a side effect which makes sense only when applied to a modifiable object. p-- is an expression. It is possible to do *p--. So we can use at least some operators on expressions, that's probably why we have the associativity rules. The ++ and -- operators require that their operands are lvalues; lvalues are expressions that refer to a region of memory such that the memory can be read or modified. In other words, ++ and -- only modify objects in memory. For example, given the following code fragment: int i = 2; int *p = &i; int j = *p++; The expressions i, j, and p are all lvalues; they all refer to a region of memory that can be read and modified. The integer constant expression 2 is not an lvalue. It does not refer to a region of memory, so an expression like 2++ would not make sense, since there's nothing to apply the side effect to. The result of an autoincrement or autodecrement expression is a value, not an lvalue; for example, given the code above, the result of the expression --i would be 1, which is not an lvalue. So writing the expression --i++ would be equivalent to writing 1++, which, again, is nonsensical. So what about expressions like *p++? The indirection operator doesn't require that its operand be an lvalue, because it's not attempting to modify a region of memory directly. Assuming that the value stored in p is 0x8000, the result of the expression p++ is the *value* 0x8000, and the dereference operator is applied to that value. > I'm having problem understanding what you mean, probably because I don't understand your definition of object and value? An object has a specific location in memory. A value doesn't. In C I know of different types of variables, constants, pointers, arrays and structs as well as enums. > int i = 10; ~!*&i++; It doesn't compile, why? The problem seems to be the ++, the compiler says: "Error: invalid l-value in unary "&"". i++ is not an object: it has no address for the & operator to return. Same question as above, what is the defintion of an object? [etc] In general, is it good programming practice to make use of the precedence and associativity of operators? It is good programming practice to use operators only in contexts for which they make sense. Why are writing arcane expressions like these when you don't have a clue what the operators do? That's the reason why I'm writing arcane expressions like this; to grasp a solid understanding of what the operators are doing to its operands and how the operators can be used. Thanks for your response!! Jan 2 '07 #9

 P: n/a dspfun said: > Why does dereferencing p-- work, e.g. *p-- works. But ++p-- doesn't work. Because ++ takes as its operand an object with scalar type. Theexpression p-- yields a value, not an object. So why does it work when you split ++p-- in two different lines?: p--; ++p; p-- decrements p, and yields as its result the old >>>*value*<<< of p, NOT the p object itself. For example, if p points to an int at address 0x1234ABCD, then p-- yields the >>>*value*<<< 0x1234ABCD (and, as a side effect, adjusts the value of p). ++0x1234ABCD makes no sense, so ++p-- doesn't make sense. But ++p; means "yield as your result the new value of p and, as a side effect, adjust the value of p". ++, in this case, is being applied to p, whereas in the (illegal) case of ++p--, you are trying to apply ++ not to p but to the value that results from evaluating the expression p--. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 2 '07 #10

 P: n/a "dspfun" San Diego Supercomputer Center <* We must do something. This is something. Therefore, we must do this. Jan 2 '07 #11

 P: n/a Thanks Richard and Keith for your help and examples!! Jan 2 '07 #12

 P: n/a Richard Heathfield wrote: dspfun said: int *p; ~!&*++p--; It doesn't compile, why? Because ++ only works on objects, and the result of p-- is an expression, This is not correct. An expression is a sequence of operators etc. p-- is an expression. Its result is not an expression; its result is a value. The compile error is because the expression p-- is not an lvalue expression. but not an object. The more I think about this statement, the more murky it seems. Better to stick to "lvalue" ! The following does compile on the other hand: int *p; p = (int *) = 0x10101010; /*Just to set it to some value..*/ No, it doesn't. Drop the second =. ~!&*p--; p results in having the value 0x1010100c which I understand why. The behaviour is undefined because p's value is changed to an invalid value. Why do you accept 10101010 as a valid value, but not one less than that? Jan 2 '07 #13

 P: n/a Old Wolf said: Richard Heathfield wrote: >dspfun said: > int *p; ~!&*++p--; It doesn't compile, why? Because ++ only works on objects, and the result of p-- is an expression, This is not correct. An expression is a sequence of operators etc. p-- is an expression. Its result is not an expression; its result is a value. If you are right, then the Standard's grammar (which says it is a postfix-expression) is wrong, and you'd better take that up with ISO. The following does compile on the other hand: int *p; p = (int *) = 0x10101010; /*Just to set it to some value..*/ No, it doesn't. Drop the second =. ~!&*p--; p results in having the value 0x1010100c which I understand why. The behaviour is undefined because p's value is changed to an invalidvalue. Why do you accept 10101010 as a valid value, but not one less than that? True, I should also have pointed out that the original assignment also invokes undefined behaviour. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 3 '07 #14

 P: n/a Richard Heathfield Richard Heathfield wrote: >>dspfun said:int *p;~!&*++p--;It doesn't compile, why?Because ++ only works on objects, and the result of p-- is an expression, This is not correct. An expression is a sequence of operators etc.p-- is an expression. Its result is not an expression; its result isa value. If you are right, then the Standard's grammar (which says it is a postfix-expression) is wrong, and you'd better take that up with ISO. p-- is an expression. The *result* of p-- is a value, not an expression. -- Keith Thompson (The_Other_Keith) ks***@mib.org San Diego Supercomputer Center <* We must do something. This is something. Therefore, we must do this. Jan 3 '07 #15

 P: n/a Keith Thompson said: Richard Heathfield Old Wolf said: >>Richard Heathfield wrote:dspfun said:int *p;~!&*++p--;It doesn't compile, why?Because ++ only works on objects, and the result of p-- is anexpression,This is not correct. An expression is a sequence of operators etc.p-- is an expression. Its result is not an expression; its result isa value. If you are right, then the Standard's grammar (which says it is apostfix-expression) is wrong, and you'd better take that up with ISO. p-- is an expression. The *result* of p-- is a value, not an expression. It's late. Or possibly early. My apologies to Old Wolf for incorrectly rejecting his correction. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 3 '07 #16

 P: n/a Groovy hepcat dspfun was jivin' on 1 Jan 2007 14:02:50 -0800 in comp.lang.c. Associativity of unary C Operators's a cool scene! Dig it! [Snip.] >Another question, when would you use the unary operator sizeof withother unary operators? To save code lines? I would use other unary operators with sizeof when that is what I need. For example, to get the size of something pointed to, I would use the dereferenced pointer as the operand of sizeof. This is often useful when dynamically allocating memory: #include some_type *ptr; ptr = malloc(sizeof *ptr); This is fine, even though the pointer has not been initialised before calling malloc(). sizeof's operand is not evaluated, except to determine the size, so the dereference is not actually performed. -- Dig the even newer still, yet more improved, sig! http://alphalink.com.au/~phaywood/ "Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker. I know it's not "technically correct" English; but since when was rock & roll "technically correct"? Jan 3 '07 #17

 P: n/a Peter "Shaggy" Haywood skrev: Groovy hepcat dspfun was jivin' on 1 Jan 2007 14:02:50 -0800 in comp.lang.c. Associativity of unary C Operators's a cool scene! Dig it! [Snip.] Another question, when would you use the unary operator sizeof with other unary operators? To save code lines? I would use other unary operators with sizeof when that is what I need. For example, to get the size of something pointed to, I would use the dereferenced pointer as the operand of sizeof. This is often useful when dynamically allocating memory: #include some_type *ptr; ptr = malloc(sizeof *ptr); This is fine, even though the pointer has not been initialised before calling malloc(). sizeof's operand is not evaluated, except to determine the size, so the dereference is not actually performed. void *p; printf("%i\",sizeof(*p)); This prints 1, why is the size of a dereferenced void pointer 1? Jan 3 '07 #18

 P: n/a dspfun wrote: > void *p; printf("%i\",sizeof(*p)); This prints 1, why is the size of a dereferenced void pointer 1? It isn't. That is a gcc (or whatever compiler you are using) extension. e.g. http://gcc.gnu.org/onlinedocs/gcc-4....#Pointer-Arith -David Jan 3 '07 #19

 P: n/a dspfun skrev: Peter "Shaggy" Haywood skrev: Groovy hepcat dspfun was jivin' on 1 Jan 2007 14:02:50 -0800 in comp.lang.c. Associativity of unary C Operators's a cool scene! Dig it! [Snip.] >Another question, when would you use the unary operator sizeof with >other unary operators? To save code lines? I would use other unary operators with sizeof when that is what I need. For example, to get the size of something pointed to, I would use the dereferenced pointer as the operand of sizeof. This is often useful when dynamically allocating memory: #include some_type *ptr; ptr = malloc(sizeof *ptr); This is fine, even though the pointer has not been initialised before calling malloc(). sizeof's operand is not evaluated, except to determine the size, so the dereference is not actually performed. void *p; printf("%i\",sizeof(*p)); This prints 1, why is the size of a dereferenced void pointer 1? printf("%i\n",sizeof(void)); This prints 1, so I guess the size of the void type is 1 byte. Jan 3 '07 #20

 P: n/a dspfun said: void *p; printf("%i\",sizeof(*p)); This prints 1, why is the size of a dereferenced void pointer 1? It's a constraint violation requiring a diagnostic message from your compiler. The compiler is free to produce executable code nonetheless, but if it does so, the Standard does not dictate what the code will do. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 3 '07 #21

 P: n/a "dspfun" =(int)sizeof p)i-=sizeof p-1;putchar(p[i]\ );}return 0;} Jan 3 '07 #22

 P: n/a dspfun said: printf("%i\n",sizeof(void)); This prints 1, so I guess the size of the void type is 1 byte. You guess wrong. Turn up the warning level on your compiler. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 3 '07 #23

 P: n/a "dspfun" San Diego Supercomputer Center <* We must do something. This is something. Therefore, we must do this. Jan 3 '07 #24

 P: n/a dspfun wrote: Peter "Shaggy" Haywood skrev: .... snip ... >>#include some_type *ptr;ptr = malloc(sizeof *ptr);This is fine, even though the pointer has not been initialisedbefore calling malloc(). sizeof's operand is not evaluated, exceptto determine the size, so the dereference is not actually performed. void *p; printf("%i\",sizeof(*p)); This prints 1, why is the size of a dereferenced void pointer 1? You are probably using gcc, without the necessary -ansi -pedantic flags. By default gcc compiles a not-C language. In that language a *void is treated as a char. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. Jan 4 '07 #25

 P: n/a CBFalconer a écrit : By default gcc compiles a not-C language. Can't you be less drastic Chuck? ALl compilers have extensions. Jan 4 '07 #26

 P: n/a jacob navia said: CBFalconer a écrit : >By default gcc compiles a not-C language. Can't you be less drastic Chuck? It's hardly drastic. It's merely accurate. > ALl compilers have extensions. None of which are topical here, since this newsgroup discusses the C language, and specific extensions are not part of the language. -- Richard Heathfield "Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk email: rjh at the above domain, - www. Jan 4 '07 #27

 P: n/a jacob navia escreveu: CBFalconer a écrit : >By default gcc compiles a not-C language. Can't you be less drastic Chuck? ALl compilers have extensions. gcc is drastic as well, isn't it? To get near to Standard conformance the switch is '-pedantic'. . . Jan 4 '07 #28

 P: n/a Cesar Rabak wrote: jacob navia escreveu: >CBFalconer a écrit : >>By default gcc compiles a not-C language. Can't you be less drastic Chuck?ALl compilers have extensions. gcc is drastic as well, isn't it? To get near to Standard conformance the switch is '-pedantic'. . . As I said in my original post. I wish people would snip in paragraph units. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. Jan 5 '07 #29

### This discussion thread is closed

Replies have been disabled for this discussion.