Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

71%
+3 −0
Q&A Cast uninitialized variable to (void)

It is undefined according to my reading of the standard (I am referring to the latest public draft). int x; (void)x; In the second line, (void)x is a full expression, but x by itself is alread...

posted 2y ago by Dirk Herrmann‭  ·  edited 2y ago by Dirk Herrmann‭

Answer
#4: Post edited by user avatar Dirk Herrmann‭ · 2022-09-14T21:26:55Z (over 2 years ago)
Changed link formatting
  • It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**. (The point about the `register` storage class is to allow optimizations on certain processors, see the explanation of "NaT" in https://devblogs.microsoft.com/oldnewthing/20150727-00/?p=90821.)
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the whole expression would be discarded: The expression just won't be discarded, only its result.
  • It is undefined according to my reading of the standard (I am referring to the [latest public draft](https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf)).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**. (The point about the `register` storage class is to allow optimizations on certain processors. See the description of the "NaT" register state in [this article about the Itanium processor](https://devblogs.microsoft.com/oldnewthing/20150727-00/?p=90821).)
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the whole expression would be discarded: The expression just won't be discarded, only its result.
#3: Post edited by user avatar Dirk Herrmann‭ · 2022-09-14T21:16:33Z (over 2 years ago)
Added explanation about the background for the `register` storage class constraint.
  • It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**.
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the whole expression would be discarded: The expression just won't be discarded, only its result.
  • It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**. (The point about the `register` storage class is to allow optimizations on certain processors, see the explanation of "NaT" in https://devblogs.microsoft.com/oldnewthing/20150727-00/?p=90821.)
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the whole expression would be discarded: The expression just won't be discarded, only its result.
#2: Post edited by user avatar Dirk Herrmann‭ · 2022-09-13T20:21:31Z (over 2 years ago)
  • It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**.
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the compiler will discard the whole expression.
  • It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).
  • int x;
  • (void)x;
  • In the second line, `(void)x` is a full expression, but `x` by itself is already an expression. For the expression `x` the following holds:
  • > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
  • Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.
  • > 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. [...]
  • As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.
  • > 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.
  • As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**.
  • Note that it does not matter that `x` is part of a larger expression `(void)x`. But, just to extend on that aspect:
  • > 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
  • Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed. The full expression will - in the end - have type `void`.
  • > 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. [...]
  • But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.
  • > 6.3.2.2 - 1: [...] If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
  • Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded. The clause is there to make it clear that a void expressions *is* evaluated. The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects. The sentence does not say that it is *only* evaluated if it has side effects.
  • Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the whole expression would be discarded: The expression just won't be discarded, only its result.
#1: Initial revision by user avatar Dirk Herrmann‭ · 2022-09-13T20:18:38Z (over 2 years ago)
It is undefined according to my reading of the standard (I am referring to the latest public draft https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf).

    int x;
    (void)x;

In the second line, `(void)x` is a full expression, but `x` by itself is already an expression.  For the expression `x` the following holds:

 > 6.5.1 - 2: An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).

Thus, `x` being an identifer that is declared to designate an `int` object implies that `x` is a primary expression and an lvalue.

> 6.3.2.1 - 2: Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.  [...]

As the lvalue `x` is the operand of a cast operator (which is not in the above exception list) and as it is also no array type it is converted into the value stored in the object designated by `x`.

> 6.3.2.1 - 2: [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

As `x` has automatic storage duration, has never its address taken and is uninitialized, **the behavior is undefined**.

Note that it does not matter that `x` is part of a larger expression `(void)x`.  But, just to extend on that aspect:

> 6.5 - 1: 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. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.

Important is the sequencing aspect here: The value of the operand `x` is computed before the result of the `(void)` operator is computed.  The full expression will - in the end - have type `void`.

> 6.3.2.2 - 1: The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression.  [...]

But this only says that you are not allowed to make further use of that `void` "result" of the expression `(void)x`.

> 6.3.2.2 - 1: [...]  If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)

Note that this does *not* say that the whole expression is discarded: Only its value (which is the result of the expression being evaluated) is discarded.  The clause is there to make it clear that a void expressions *is* evaluated.  The sentence in parentheses gives the reason why it is evaluated, namely because it may have side effects.  The sentence does not say that it is *only* evaluated if it has side effects.

Therefore, it is also not possible to argue that the "undefinedness" stated above becomes irrelevant because the compiler will discard the whole expression.