In what version(s) of the C standards (if any) is the following well-defined?
void foo(void) {
char *nullPtr = NULL;
&*nullPtr;
}
Note that I am not assigning the result to anything - the second line is a simple statement.
This should be a question with an obvious answer, but (as seemingly happens way too often on such questions) I have heard just as many people say the answer is "obviously undefined" as "obviously defined".
On a rather related note, what about the following? Should foo produce a read of c?
extern volatile char c;
void bar(void) {
volatile char *nonnullptr = &c;
&*nonnullptr;
}
(C++ version of the same question: Is &*NULL well-defined in C++?)
While attempts to dereference a null pointer cause undefined behavior, so *nullPtr is illegal, &*nullPtr is perfectly well-defined. According to footnote 102 in the C11 Draft Standard:
Thus, &*E is equivalent to E (even if E is a null pointer),....
This is a result of the fact that, for the unary & operator (§6.5.3.2 ¶3):
If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted,....
The C99 Standard has the same language, but this does not appear in the C90 Standard, and my reading of that standard is that &*nullPtr would indeed cause undefined behavior in pre-C99 implementations.
From the C90 Standard (§6.3.2.3):
The result of the unary & (address-of) operator is a pointer to the object or function designated by its operand....
and:
The unary * operator denotes indirection.... If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Curiously, I don't see any discussion of this change in the C99 Rationale, though I may just be not finding it.
Related
Is a C implementation required to ignore undefined behaviors occurring during the evaluation of void expressions as if the evaluation itself never took place?
Considering C11, 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.)
This is related to the common idiom used to prevent compilers from warning about unused variables:
void f() {
int a;
(void)a;
}
But what if we have undefined behavior, such as:
void f() {
int a;
(void)(1/0);
}
Can I safely claim that this program contains no undefined behavior? The standard says that "its value or designator is discarded", but the "expression (...) is evaluated (...)", so the evaluation does seem to take place.
GCC/Clang do report the undefined behavior, since it is obvious in this case, but in a more subtle example they don't:
int main() {
int a = 1;
int b = 0;
(void)(a/b);
return 0;
}
Even with -O0, neither GCC nor Clang evaluate 1/0. But that also happens even without the cast to void, so it's not representative.
Pushing the argument to its extreme, wouldn't the simple evaluation of (void)a in my first example (where a is uninitialized) systematically trigger undefined behavior?
ISO C11 6.3.2.1 §2 does mention that:
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.
However, in the Annex J.2 Undefined behavior, the phrasing is slightly different:
The behavior is undefined in the following circumstances:
(...)
An lvalue designating an object of automatic storage duration that could have been declared with the register storage class is used in a context that requires the value of the designated object, but the object is uninitialized. (6.3.2.1).
This annex does lead to the interpretation that a void expression containing undefined behavior during its evaluation is not actually evaluated, but since it's just an annex, I'm not sure of its argumentative weight.
This is related to the common idiom used to prevent compilers from
warning about unused variables:
void f() {
int a;
(void)a;
}
Yes and no. I'd argue that that idiom turns an unused variable into a used one -- it appears in an expression -- with the cast to void serving to prevent compilers from complaining about the result of that expression going unused. But in the technical, language-lawyer sense, that particular expression of the idiom produces UB because the sub-expression a is subject to lvalue conversion when a's value is indeterminate. You've already quoted the relevant text of the standard.
But what if we have undefined behavior, such as:
void f() {
int a;
(void)(1/0);
}
Can I safely claim that this program contains no undefined behavior?
No.
The standard says that "its value or designator is discarded", but the
"expression (...) is evaluated (...)", so the evaluation does seem to
take place.
Yes, just as the expression a in your earlier example is also evaluated, also producing UB. UB arises from evaluation of the inner sub-expression. The conversion to type void is a separable consideration, exactly as a conversion to any other type would be.
GCC/Clang do report the undefined behavior, since it is obvious in
this case, but in a more subtle example they don't:
Compiler behavior cannot be taken as indicative here. C does not require compilers to diagnose most undefined behaviors, not even those that could, in principle, be detected at compile time. Indeed, it is important to recognize that UB arising from incorrect code happens first and foremost at compile time, though of course it follows that if an executable is produced then it exhibits UB, too.
Pushing the argument to its extreme, wouldn't the simple evaluation of
(void)a in my first example (where a is uninitialized) systematically
trigger undefined behavior?
Yes, as I already remarked. But that does not mean that programs containing such constructions are obligated to misbehave. As a quality-of-implementation matter, I think it reasonable to hope that the expression statement (void)a; will be accepted by the compiler and will have no corresponding runtime behavior at all. But I cannot rely on the language standard to back me up on that.
This annex does lead to the interpretation that a void expression
containing undefined behavior during its evaluation is not actually
evaluated, but since it's just an annex, I'm not sure of its
argumentative weight.
The plain wording of the normative text of the standard is quite sufficient here. The annex is not normative, but if there is any question about how the normative text is meant to be interpreted, then informative sections of the standard, such as Annex J, are one of the sources taken into account in sorting that out (but they are still only informative).
In C programming, comparing two different types of pointers like this :
int i = 1;
double d = 2.5;
int *ip = &i;
double *dp = &d;
if(ip != dp) // is it UB?
printf("Not same\n");
Is ip != dp undefined behaviour in C?
The direct comparison ip != dp is invalid in C. Specification of != operator does not allow mixing int * and double * pointers in one comparison. It is a constraint violation in C (aka a "compile error"). A conforming C compiler will report your code as invalid by issuing a diagnostic message.
What happens next depends solely on your compiler. It has nothing to do with C language.
Referring to this code as "C code that produces undefined behavior" would be misleading. It is formally true, but it makes exactly as much sense as saying that the text of "War and Piece" is "C code that produces undefined behavior" (in some strange C compiler that accepts it).
The key point here is that this code language constraints meaning that it is not C code at all.
This is not well defined. A prerequisite of the != operator is that if both operands are pointers, they must be to compatible types. int and double are not compatible types.
From section 6.5.9 of the C standard:
2 One of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of
compatible types;
— one operand is a pointer to an object type and the other is a
pointer to a qualified or unqualified version of void; or
— one operand is a pointer and the other is a null pointer constant.
Yes this operation is undefined, and Kernighan & Ritchie were mentioned about that in their book "The C Programming Language":
Any pointer can be meaningfully compared for equality or inequality with zero. But the behavior is undefined for arithmetic or comparisons with pointers that do not point to members of the same array.
This means that pointers that points to different types cannot be checked for equality.
This question already has answers here:
Using & (addressof) with const variables in C
(3 answers)
Closed 5 years ago.
According to The C programming language by Kernighan and Ritchie, page 94
& operator cannot be applied to constants
const int u = 9;
printf ("\nHello World! %u ", &u);
So, why does that work?
You are misunderstanding between constant and const. Both are different things in C language.
& operator cannot be applied to constants
In C programming, It means you cannot use &(address operator) on the literal constant to get the address of the literal constant.
For examples :
&10
or
&('a')
If you use & operator over literal constant, the compiler will give an error because constant entity does not have corresponding address.
According to the Draft Standard §6.5.3.2 ¶1, use of the address operator must obey the following constraint:
The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
The meaning of lvalue is given in §6.3.2.1 ¶1:
An lvalue is an expression (with an object type other than void) that potentially designates an object.
According to §3.15 ¶1 an object is a:
region of data storage in the execution environment, the contents of which can represent values.
Now, a constant is not an lvalue; a constant has a value, but a constant does not indicate an object, and a value can't be assigned to a constant.
So, a constant is not a function designator, is not the result of a [] or unary * operator, and is not an lvalue, which means that taking the address of a constant is a constraint violation. A diagnostic message must be issued by a conforming implementation.
On the other hand, given const int u = 9;, u is a const qualified variable of type int. This declaration does reserve storage for the variable, and u is an lvalue. The use of const does not indicate that u is a constant, but that the object indicated by the identifier u is const (which is not the same thing). It may be better to think of const qualified variables as "read-only"; this is a promise made by the program that the object indicated by u will not be modified. Since u is an lvalue here (that is not a bit-field, and is not declared with the register keyword), it is fine to take its address with &u.
Do note that the posted code has undefined behavior, since the correct printf() conversion specifier for printing addresses is %p; its argument must be cast to (void *). Mismatched conversion specifiers and arguments lead to undefined behavior. So, the correct code would be:
const int u = 9;
printf ("\nHello World! %p ", (void *) &u);
No, in order to get variable's address in the memory, we can apply pointer to any of them, coz CPU allocates memory for all of them. On the other hand this question has already been asked.
The term "constant" in C indeed means only literal constants, like 2, for example. A const-qualified object is not a "constant" in C terminology
Link to question
I know that C & C++ both are different languages, today I make a little typo in the following program but the program compiles fine on various C++ compilers (g++,clang,MSVC++)
Consider following program:
int main()
{
int s[]={3,6,9,12,18};
int* p=+s; // Observe this strange looking initialization due to use of unary + operator
}
The above program compiles fine in C++ (See live demo here) but not in C (See live demo here.) My compiler ( gcc 4.8.1 ) gives me following error when I compile it as a C program.
[Error] wrong type argument to unary plus
What purpose the unary plus operator serves here? What it does exactly here? Why it is not allowed in C?
The section 6.5.3.3 of C99 states:
1) The operand of the unary + or - operator shall have arithmetic type;
......
2) The result of the unary + operator is the value of its (promoted)
operand. The integer promotions are performed on the operand, and the
result has the promoted type.
Pointers or arrays are not an arithmetic type.
What purpose the unary plus operator serves here?
In C++, the behavior is laid out in section 5.3.1:
[2] The result of each of the following unary operators is a prvalue.
[7] The operand of the unary + operator shall have arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument.
Sometimes people use this operator to "force" decay, i.e. in this case an array to pointer. But it is rather redundant since the conversion happens automatically.
What it does exactly here? Why it is not allowed in C?
Because the special meaning simply does not exist.
s will be treated as a pointer not as an array when + operator is called.
For C, it seems that this concept was not introduced yet.
I have only ever seen this used in situations where the unary + operator has been overloaded in an OOP language like C++. It hasn't got a purpose in C apart from possible causing errors like this where a pointer was accidentally passed to a macro or a function that does not expect one.
Either way it's a nasty way to write code, if there was a good reason for it then it should be accompanied by an explanatory comment from the original author.
With some friends we discuss about the corectness of this simple following code in ANSI C.
#include <stdio.h>
int main(void)
{
int a=2;
printf("%d", *&a);
return 0;
}
The main discuss is about *&. If * access a memory location (aka pointer) and & gives memory address of some variable... I think * tries to access a int value as memory adress ( that obviously don't work), but my friend says *& it cancels automatically ( or interpret as &*). We tested it with GCC 4.8.1 (MinGW) and the code avobe worked it well... I think was not right.
What do you think about? Think there's a bad workaround here ( or this is just stupidity?). Thanks in advice :)
a is an lvalue: the variable a.
&a is a pointer to this lvalue.
*&a is the lvalue being pointed to by &a — that is, it is a.
Technically speaking, *&a and a are not completely equivalent in all cases, in that *&a is not permitted in all circumstances where a is (for example, if a is declared as register), but in your example, they are completely the same.
There is an interesting excerpt from C standard (as a footnote), namely C11 §6.5.3.2/4 (footnote 102, emphasis mine), which discusses this aspect directly:
Thus, &*E is equivalent to E (even if E is a null pointer), and
&(E1[E2]) to ((E1)+(E2)). It is always true that if E is a function
designator or an lvalue that is a valid operand of the unary &
operator, *&E is a function designator or an lvalue equal to E. If *P
is an lvalue and T is the name of an object pointer type, *(T)P is an
lvalue that has a type compatible with that to which T points.
In your case a is a (modifiable) lvalue, that reflects to E symbol from standard and it's valid operand of the & operator as standard requires, thus *&a (i.e. *&E) is an lvalue equal to a.
Note that you can't take address of register storage class variable (as pointed by #Deduplicator), so it does not qualify into such reduction (that is, even as modifiable lvalue).
So long as *&a is meaningful, then *&a and a are the same thing and are interchangeable.
In general, *&a is the same as a.
Still, there are corner-cases:
*& may be invalid because &a is not allowed, as it is not an lvalue or it is of register-storage-class.
Using a may be Undefined Behavior, because a is an uninitialized memory-less variable (register or auto-storage-class which might have been declared register (address was never taken)).
Applying that to your case, leaving out *& does not change anything.