C++ ANSI ISO IEC 14882 2003 Annex C.1 (page 668):
Change: The result of a conditional expression, an assignment expression, or a comma expression may bean lvalue
Rationale: C + + is an object-oriented language, placing relatively more emphasis on lvalues. For example, functions may return lvalues.
Effect on original feature: Change to semantics of well-defined feature. Some C expressions that implicitly rely on lvalue-to-rvalue conversions will yield different results. For example,
char arr[100];
sizeof(0, arr)
yields 100 in C + + and sizeof(char*) in C.
...
I was reading this just today and I remembered that a couple of months a go a friend of mine proposed a problem wchich was to write a function that would return 0 if it were compiled with C++ and 1 if it were compiled with C. I solved it taking advantage of the fact that in C a struct was in the outer scope. So, considering this new information, I decided that this would be another solution to the above problem, which I tried on Microsoft Visual Studio 2008, but regardless of whether it is compiled as C or C++ code sizeof(0, arr) always yields 4. So 2 questions:
1.What is ISO C? Is it the current C standard? Is it the only one (I hear C is rapidly evolving)
2. Is this a microsoft C++ bug?
TIA
Edit: Sorry got mixed up with the output and edited it:
ISO C is the C standard. The current one is C99 but C1x is right around the corner. If by rapid, you mean a new standard every decade or so, then yes, it is rapidly evolving :-)
Section 6.5.3.4/3 of ISO C99 states:
When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.
When applied to an operand that has array type, the result is the total number of bytes in the array.
Or just microsoft's C is not ISO C but some other standard C (if there exists any).
Microsoft Visual C still supports C89 [only] whereas other compilers like gcc/clang etc support C99 too which is the current Standard.
C99 [Section 6.5.17/2] says
The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.95
Thus the result of sizeof (0,arr) would be sizeof(char*)[due to the implicit lvalue to rvalue conversion /automatic decay to pointer type] not 100*sizeof(char)
sizeof(arr) would have given 100*sizeof(char) from 6.5.3.4/3
95) A comma operator does not yield an lvalue.
decided that this would be another solution to the above problem, which I tried on Microsoft Visual Studio 2008, but regardless of whether it is compiled as C or C++ code sizeof(0, arr) always yields 4.
C++03 [5.18/1] Comma Operator
The type and
value of the result are the type and value of the right operand; the result is an lvalue if its right operand is.
So sizeof(0, arr) = sizeof (arr) and which would be equal to 100* sizeof(char) and not = sizeof(char*).
So MSVC++ is giving incorrect result (in case of C++ code).
For arrays, the sizeof returns the total size. Be careful about arrays passed as pointers.
C99 standard:
When applied to an operand that has array
type, the result is the total number of bytes in the array
Related
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 specifically asking about &*nullPtr here. I am aware that simply *nullPtr is undefined - but this is a separate question and hence the currently-linked "duplicate" is not a duplicate.
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?)
This is four questions in one.
&*nullPtr is well-defined in C since C99, which says of the unary & operator:
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, [...]
See WG14 N721 and DR076.
&*nullPtr is formally undefined in all revisions of C++ (by omission: unary & is specified to produce a pointer to "the designated object", and unary * is specified to produce "an lvalue referring to the object [...] to which the expression points"; a null pointer value points to no object), although the direction of core issue 232 is to make this well-defined.
&*nonnullptr produces no volatile read of *nonnullptr. Unary & expects an lvalue operand; no lvalue conversion (for C) or lvalue-to-rvalue conversion (for C++) is performed for *nonnullptr.
How portable is this conversion. Can I be sure that both assertions pass?
int x = 4<5;
assert(x==1);
x = 4>5;
assert(x==0);
Don't ask why. I know that it is ugly. Thank you.
int x = 4<5;
Completely portable. Standard conformant. bool to int conversion is implicit!
§4.7/4 from the C++ 11 or 14 Standard, §7.8/4 from the C++ 17 Standard, §7.3.9/2 from the 20 Standard says (Integral Conversion)
If the source type is bool, the value false is converted to zero and
the value true is converted to one.
As for C, as far as I know there is no bool in C. (before 1999) So bool to int conversion is relevant in C++ only. In C, 4<5 evaluates to int value, in this case the value is 1, 4>5 would evaluate to 0.
EDIT: Jens in the comment said, C99 has _Bool type. bool is a macro defined in stdbool.h header file. true and false are also macro defined in stdbool.h.
§7.16 from C99 says,
The macro bool expands to _Bool.
[..] true which expands to the integer constant 1, false
which expands to the integer constant 0,[..]
You tagged your question [C] and [C++] at the same time. The results will be consistent between the languages, but the structure of the the answer is different for each of these languages.
In C language your examples has no relation to bool whatsoever (that applies to C99 as well). In C language relational operators do not produce bool results. Both 4 > 5 and 4 < 5 are expressions that produce results of type int with values 0 or 1. So, there's no "bool to int conversion" of any kind taking place in your examples in C.
In C++ relational operators do indeed produce bool results. bool values are convertible to int type, with true converting to 1 and false converting to 0. This is guaranteed by the language.
P.S. C language also has a dedicated boolean type _Bool (macro-aliased as bool), and its integral conversion rules are essentially the same as in C++. But nevertheless this is not relevant to your specific examples in C. Once again, relational operators in C always produce int (not bool) results regardless of the version of the language specification.
Section 6.5.8.6 of the C standard says:
Each of the operators < (less than), >
(greater than), <= (less than or equal
to), and >= (greater than or equal to)
shall yield 1 if the specified
relation is true and 0 if it is
false.) The result has type int.
There seems to be no problem since the int to bool cast is done implicitly. This works in Microsoft Visual C++, GCC and Intel C++ compiler. No problem in either C or C++.
According to cppreference section Core constant expressions point 19) a subtraction operator between two pointers is not legal constant expression until c++14. Can I assume that following code is legal c++17 code or is this interpretation an abuse?
int X, Y;
template <long long V>
struct S { };
int main() {
S<&X - &Y> s;
(void)s;
}
The question is moot. Pointer arithmetics is only defined on the pointers belonging to the same array, which is certainly not the case there. So, the code above is not legal C++, and in fact, fails to compile with compilers available to me.
The quoted cppref article says
A core constant expression is any expression that does not have any
one of the following ..
7) An expression whose evaluation leads to any form of core language
(since C++17) undefined behavior (including signed integer overflow,
division by zero, pointer arithmetic outside array bounds, etc).
Whether standard library undefined behavior is detected is
unspecified. (since C++17)
19) a subtraction operator between two pointers(until C++14)
Likely only array ptr arithemtics inside array bounds is getting 'legalized' since c++14, not all pointer arithmetics
Actually a demo shows that array ptr arithmetics compiles alright even with c++11 (not c++98)
What is the unary-& doing here?
int * a = 1990;
int result = &5[a];
If you were to print result you would get the value 2010.
You have to compile it with -fpermissive or it will stop due to errors.
In C, x [y] and y [x] are identical. So &5[a] is the same as &a[5].
&5[a] is the same as &a[5] and the same as a + 5. In your case it's undefined behavior because a points to nowhere.
C11 standard chapter 6.5.6 Additive operators/8 (the same in C++):
If both the pointer
operand and the result point to elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined.
"...unary & on numeric literal"?
Postfix operators in C always have higher priority than prefix ones. In case of &5[a], the [] has higher priority than the &. Which means that in &5[a] the unary & is not applied to "numeric literal" as you seem to incorrectly believe. It is applied to the entire 5[a] subexpression. I.e. &5[a] is equivalent to &(5[a]).
As for what 5[a] means - this is a beaten-to-death FAQ. Look it up.
And no, you don't have "to compile it with -fpermissive" (my compiler tells me it doesn't even know what -fpermissive is). You have to figure out that this
int * a = 1990;
is not legal code in either C or C++. If anything, it requires an explicit cast
int * a = (int *) 1990;
not some obscure switch of some specific compiler you happened to be using at the moment. The same applies to another illegal initialization in int result = &5[a].
Finally, even if we overlook the illegal code and the undefined behavior triggered by that 5[a], the behavior of this code will still be highly implementation-dependent. I.e. the answer is no, in general case you will not get 2010 in result.
You cannot apply the unary & operator to an integer literal, because a literal is not an lvalue.
Due to operator precedence, your code doesn't do that. Since the indexing operator [] binds more tightly than unary &, &5[a] is equivalent to &(5[a]).
Here's a program similar to yours, except that it's valid code, not requiring -fpermissive to compile:
#include <stdio.h>
int main(void) {
int arr[6];
int *ptr1 = arr;
int *ptr2 = &5[ptr1];
printf("%p %p\n", ptr1, ptr2);
}
As explained in this question and my answer, the indexing operator is commutative (because it's defined in terms of addition, and addition is commutative), so 5[a] is equivalent to a[5]. So the expression &5[ptr1] computes the address of element 5 of arr.
In your program:
int * a = 1990;
int result = &5[a];
the initialization of a is invalid because a is of type int* and 1990 is of type int, and there is no implicit conversion from int to int*. Likewise, the initialization of result is invalid because &5[a] is of type int*. Apparently -fpermissive causes the compiler to violate the rules of the language and permit these invalid implicit conversions.
At least in the version of gcc I'm using, the -fpermissive option is valid only for C++ and Objective-C, not for C. In C, gcc permits such implicit conversions (with a warning) anyway. I strongly recommend not using this option. (Your question is tagged both C and C++. Keep in mind that C and C++ are two distinct, though closely related, languages. They happen to behave similarly in this case, but it's usually best to pick one language or the other.)
We all know that dereferencing an null pointer or a pointer to unallocated memory invokes undefined behaviour.
But what is the rule when used within an expression passed to sizeof?
For example:
int *ptr = 0;
int size = sizeof(*ptr);
Is this also undefined?
In most cases, you will find that sizeof(*x) does not actually evaluate *x at all. And, since it's the evaluation (de-referencing) of a pointer that invokes undefined behaviour, you'll find it's mostly okay. The C11 standard has this to say in 6.5.3.4. The sizeof operator /2 (my emphasis in all these quotes):
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
This is identical wording to the same section in C99. C89 had slightly different wording because, of course, there were no VLAs at that point. From 3.3.3.4. The sizeof operator:
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand, which is not itself evaluated. The result is an integer constant.
So, in C, for all non-VLAs, no dereferencing takes place and the statement is well defined. If the type of *x is a VLA, that's considered an execution-phase sizeof, something that needs to be worked out while the code is running - all others can be calculated at compile time. If x itself is the VLA, it's the same as the other cases, no evaluation takes place when using *x as an argument to sizeof().
C++ has (as expected, since it's a different language) slightly different rules, as shown in the various iterations of the standard:
First, C++03 5.3.3. Sizeof /1:
The sizeof operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is not evaluated, or a parenthesized type-id.
In, C++11 5.3.3. Sizeof /1, you'll find slightly different wording but the same effect:
The sizeof operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is an unevaluated operand (Clause 5), or a parenthesized type-id.
C++11 5. Expressions /7 (the above mentioned clause 5) defines the term "unevaluated operand" as perhaps one of the most useless, redundant phrases I've read for a while, but I don't know what was going through the mind of the ISO people when they wrote it:
In some contexts ([some references to sections detailing those contexts - pax]), unevaluated operands appear. An unevaluated operand is not evaluated.
C++14/17 have the same wording as C++11 but not necessarily in the same sections, as stuff was added before the relevant parts. They're in 5.3.3. Sizeof /1 and 5. Expressions /8 for C++14 and 8.3.3. Sizeof /1 and 8. Expressions /8 for C++17.
So, in C++, evaluation of *x in sizeof(*x) never takes place, so it's well defined, provided you follow all the other rules like providing a complete type, for example. But, the bottom line is that no dereferencing is done, which means it does not cause a problem.
You can actually see this non-evaluation in the following program:
#include <iostream>
#include <cmath>
int main() {
int x = 42;
std::cout << x << '\n';
std::cout << sizeof(x = 6) << '\n';
std::cout << sizeof(x++) << '\n';
std::cout << sizeof(x = 15 * x * x + 7 * x - 12) << '\n';
std::cout << sizeof(x += sqrt(4.0)) << '\n';
std::cout << x << '\n';
}
You might think that the final line would output something vastly different to 42 (774, based on my rough calculations) because x has been changed quite a bit. But that is not actually the case since it's only the type of the expression in sizeof that matters here, and the type boils down to whatever type x is.
What you do see (other than the possibility of different pointer sizes on lines other than the first and last) is:
42
4
4
4
4
42
No. sizeof is an operator, and works on types, not the actual value (which is not evaluated).
To remind you that it's an operator, I suggest you get in the habit of omitting the brackets where practical.
int* ptr = 0;
size_t size = sizeof *ptr;
size = sizeof (int); /* brackets still required when naming a type */
The answer may well be different for C, where sizeof is not necessarily a compile-time construct, but in C++ the expression provided to sizeof is never evaluated. As such, there is never a possibility for undefined behavior to exhibit itself. By similar logic, you can also "call" functions that are never defined [because the function is never actually called, no definition is necessary], a fact that is frequently used in SFINAE rules.
sizeof and decltype do not evaluate their operands, computing types only.
sizeof(*ptr) is the same as sizeof(int) in this case.
Since sizeof does not evaluate its operand (except in the case of variable length arrays if you're using C99 or later), in the expression sizeof (*ptr), ptr is not evaluated, therefore it is not dereferenced. The sizeof operator only needs to determine the type of the expression *ptr to get the appropriate size.