2

Does the C99 standard allow variables to be assigned to themselves? For instance, are the following valid:

int a = 42;

/* Case 1 */
a = a;

/* Case 2 */
int *b = &a;
a = *b;

While I suspect Case 1 is valid, I'm hesitant to say the same for Case 2.

In the case of an assignment, is the right side completely evaluated before assigning the value to the variable on the left -- or is a race condition introduced when dereferencing a pointer to the variable being assigned?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • 1
    `a = a;` is dead instruction in high level languages, I am pretty sure optimization phase will remove it – Grijesh Chauhan Jul 17 '13 at 15:35
  • 1
    @GrijeshChauhan Not always if a is in memory and optimisation is not required. See my example below. – hivert Jul 17 '13 at 15:38
  • 2
    As long as the variable is already properly initialized, you should be OK. If the variable is not initialized, copying the uninitialized value doesn't make it any better initialized. If the variable is `volatile`, it might not be a no-op (the compiler is obliged to read the value and write the value that was read back again). When the variable is not qualified with `volatile`, it should be a no-op. – Jonathan Leffler Jul 17 '13 at 16:21

5 Answers5

4

Both cases are perfectly valid, since the value of a is only used to determine the value that is to be stored, not to determine the object in which this value is to be store.

In essence in an assignment you have to distinguish three different operations

  • determine the object to which the value is to be stored
  • evaluate the RHS
  • store the determined value in the determined object

the first two of these three operations can be done in any order, even in parallel. The third is obviously a consequence of the two others, so it will come after.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
3

This is perfectly valid, you are only using the previous value to determine the value to be stored. This is covered in the draft C99 standard section 6.5.2 which says:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.Furthermore, the prior value shall be read only to determine the value to be stored.

One of the examples of valid code is as follows:

i = i + 1;

The C and C++ section here covers the different places where a sequence point can occur.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

Assuming the compiler doesn't optimize the first instruction out by simply removing it, there is even a race condition here. On most architecture, if a is stored in memory a = a will be compiled in two move instructions (mem => reg, reg => mem) and therefore is not atomic.

Here is an example:

int a = 1;
int main() 
{ a = a; }

Result on an Intel x86_64 with gcc 4.7.1

4004f0:       8b 05 22 0b 20 00       mov    0x200b22(%rip),%eax        # 601018 <a>
4004f6:       89 05 1c 0b 20 00       mov    %eax,0x200b1c(%rip)        # 601018 <a>
hivert
  • 10,579
  • 3
  • 31
  • 56
  • but you are *assuming*, did you try it? Why not any compiler not remove it? it easy to do detect. Is it your real example?? Which compiler? – Grijesh Chauhan Jul 17 '13 at 15:41
  • Although @GrijeshChauhan is probably correct that modern compilers would most likely not do this, I am interested in whether the C99 standard allows this behavior -- after all, a compiler doesn't have to be *practical* to be *standards-compliant*. – Vilhelm Gray Jul 17 '13 at 16:38
  • hmm hivert putted what it would be if compiler not optimize it so its good answer. – Grijesh Chauhan Jul 17 '13 at 16:53
2

C99 6.5.16.1 Simple assignment

3 If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.

I think the example code qualifies the "overlap" condition. Since they do have qualified version of a compatible type, the result is valid.

Also 6.5.16 Assignment operators

4 The order of evaluation of the operands is unspecified. If an attempt is made to modify the result of an assignment operator or to access it after the next sequence point, the behavior is undefined.

Still, there's no "attempt to modify the result" so the result is valid.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Regarding paragraph 4 (`If an attempt is made to modify the result of an assignment operator or to access it after the next sequence point, the behavior is undefined.`), would this thus be undefined since `a` is modified before it is evaluated: `a = ++a`? What is a *sequence point*? – Vilhelm Gray Jul 17 '13 at 16:33
  • 1
    @VilhelmGray This is a good reference on sequence points: http://en.wikipedia.org/wiki/Sequence_point it has a section on C and C++ and what counts as a sequence point. – Shafik Yaghmour Jul 17 '13 at 16:38
  • @VilhelmGray Yes, that is correct, slide 197 has this example: http://www.slideshare.net/olvemaudal/deep-c and this page has many more such examples: https://www.securecoding.cert.org/confluence/display/seccode/EXP30-C.+Do+not+depend+on+order+of+evaluation+between+sequence+points – Shafik Yaghmour Jul 17 '13 at 16:50
  • @ShafikYaghmour Sorry I deleted my earlier comment. Were you referring to `int c = ++a + a` being undefined, or `a = ++a`; or are both undefined? – Vilhelm Gray Jul 17 '13 at 16:55
  • 1
    @VilhelmGray Your previously asked about `c = ++a + a` but both of your example are undefined. – Shafik Yaghmour Jul 17 '13 at 16:56
  • Thanks for the clarification. I do have one final case to solidify my understanding. `a = ++a` is invalid since it attempts to modify the stored value of `a` twice before the next sequence point. Is this true even when the left hand object isn't in the right hand expression? Is it correct to say that this is valid: `int c = ++a`; but this is invalid: `int c = ++(++a)` since `a` is modified more than once before the next sequence point? – Vilhelm Gray Jul 17 '13 at 17:04
  • Actually I don't think `++(++a)` is syntactically valid C, but I still wonder about multiple modifications to a stored value. – Vilhelm Gray Jul 17 '13 at 17:08
  • @VilhelmGray I am pretty sure `c = ++a` is ok: http://c-faq.com/expr/confused.html – Shafik Yaghmour Jul 17 '13 at 17:49
  • 1
    @VilhelmGray; In case of expression `c = ++(++a), the result of the post-increment (a++) is not an l-value, i.e. it can't be post-incremented again. See this [link](http://stackoverflow.com/a/5341398/2455888) – haccks Jul 17 '13 at 18:21
0

I can't see a C compiler not permitting a = a. Such an assignment may occur serendipitously due to macros without a programmer knowing it. It may not even generate any code for that is an optimizing issue.

#define FOO (a)
...
a = FOO;

Sample code readily compiles and my review of the C standard shows no prohibition.

As to race conditions @Yu Hao answers that well: no race condition.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256