#include <iostream>
using namespace std;
typedef int MYINT;
int main()
{
int y = MYINT(); // As expected, y = 0; value initialization
cout << MYINT(); // Error
cout << sizeof(MYINT()); // Error
}
Why the last two lines in the main function before the closing brace give error? Why is the expression MYINT() treated differently in different contexts? Any Standard reference will be helpful.
MYINT() can, depending on context, be interpreted as an expression of type MYINT, or a specifier of a function type taking no arguments and returning MYINT.
In some situations, where either an expression or a type specifier is valid, this gives an ambiguity; this is resolved by interpreting it as a type specifier if possible (EDIT: C++03 8.2/2, if you want a Standard reference).
sizeof can take either an expression, or a parenthesised type specifier, as it's argument, giving this ambiguity. So here MYINT() is interpreted as a type specifier; then you get an error, since sizeof can't be applied to a function type.
EDIT: You can fix the error by removing the parentheses so it will be interpreted as an expression (sizeof MYINT()), adding extra parentheses so it isn't a valid type specifier (sizeof((MYINT()))), or changing it to the correct type (sizeof(MYINT)).
cout << MYINT() is unambiguous, so there should be no error, and indeed there isn't on my compiler. What is the error, and what is your compiler?
If your MINTINT is typedef int MYINT then MYINT() is not a function but is int() which is a default initialization, equivallent to int y = 0 or int y = int(0).
Your second line, ie cout << MYINT() compiles correctly for me with g++ -Wall -ansi -pedantic for the same reason.
But g++ will complain for the sizeof with the following error error: invalid application of "sizeof" to a function type because it interprets MYINT() as "a call to a default constructor for int" (EDIT: this is not correct) "a function type returning MYINT which is not allowed" (EDIT: this is the correct answer, see Mike's). But this a nothing to do with the typedef.
Summary:
#include <iostream>
typedef int myint;
int main()
{
int y = myint();
int z = myint(0);
std::cout << y << z; // Will output 0 0
std::cout << std::endl << myint(0) << myint(); // Will output 0 0
std::cout << sizeof(int()); // The error is here; same with sizeof(myint())
}
Edit (again)
As said in the comment is the cout lines doesn't work for you, this is because you probably forgot to include <iostream>.
Edit
Look also the answer of Mike Seymour for an explanation of the ambiguity with sizeof.
// OK. Implicit conversion to int.
int y = MYINT();
// OK. Implicit conversion again. Which compiler do you use?
cout << MYINT();
// Invalid. Tries to get size of a function that returns MYINT,
// because sizeof expects a type-id and according to 8.2/2,
// which is forbidden according to the C++ Standard 5.3.3/1
cout << sizeof(MYINT());
// Do you want this instead?
cout << sizeof(MYINT);
I do not see any error for the cout << MYINT(); line. However I see invalid application of 'sizeof' to a function type for the cout << sizeof(MYINT()); line. The problem is the () around MYINT(). The C++ standard says this about sizeof and how it is parsed:
sizeof unary-expression
sizeof ( type-id )
There is a parsing ambiguity between sizeof unary-expression and sizeof ( type-id ). It is resolved by using longer match. It parses sizeof (MYINT()) as sizeof ( type-id ), MYINT() is a function type and thus you see the error.
Why the last two lines in the main function before the closing brace give error?
cout << MYINT(); doesn't work because cout is not defined. Once you do #include <iostream> and using std::cout, it will work fine.
sizeof(MYINT()) does indeed not work, but sizeof(int()) doesn't work either, so that's to be expected. sizeof(MYINT) will work just fine.
Why is the expression MYINT() treated differently in different contexts?
It's not. In every case MYINT() behaves exactly like int().
Related
What is the difference between
(type)value
and
type(value)
in C++?
There is no difference; per the standard (§5.2.3):
A simple-type-specifier (7.1.5) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4).
Since the question specified the difference between type(value) and (type)value, there is absolutely no difference.
If and only if you're dealing with a comma-separated list of values can there be a difference. In this case:
If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as an rvalue.
As Troubadour pointed out, there are a certain names of types for which the type(value) version simply won't compile. For example:
char *a = (char *)string;
will compile, but:
char *a = char *(string);
will not. The same type with a different name (e.g., created with a typedef) can work though:
typedef char *char_ptr;
char *a = char_ptr(string);
There is no difference; the C++ standard (1998 and 2003 editions) is clear about this point. Try the following program, make sure you use a compiler that's compliant, such as the free preview at http://comeaucomputing.com/tryitout/.
#include <cstdlib>
#include <string>
int main() {
int('A'); (int) 'A'; // obvious
(std::string) "abc"; // not so obvious
unsigned(a_var) = 3; // see note below
(long const&) a_var; // const or refs, which T(v) can't do
return EXIT_SUCCESS;
}
Note: unsigned(a_var) is different, but does show one way those exact tokens can mean something else. It is declaring a variable named a_var of type unsigned, and isn't a cast at all. (If you're familiar with pointers to functions or arrays, consider how you have to use a parens around p in a type like void (*pf)() or int (*pa)[42].)
(Warnings are produced since these statements don't use the value and in a real program that'd almost certainly be an error, but everything still works. I just didn't have the heart to change it after making everything line up.)
There is no difference when both are casts, but sometimes 'type(value)' is not a cast.
Here's an example from standard draft N3242, section 8.2.1:
struct S
{
S(int);
};
void foo(double a)
{
S w( int(a) ); // function declaration
S y( (int)a ); // object declaration
}
In this case 'int(a)' is not a cast because 'a' is not a value, it is a parameter name surrounded by redundant parentheses. The document states
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 can also occur in the context
of a declaration. In that context, the choice is between a function
declaration with a redundant set of parentheses around a parameter
name and an object declaration with a function-style cast as the
initializer. Just as for the ambiguities mentioned in 6.8, the
resolution is to consider any construct that could possibly be a
declaration a declaration.
In c there is no type (value), while in c/c++ both type (value) and (type) value are allowed.
To illustrate your options in C++ (only one has a safety check)
#include<boost/numeric/conversion/cast.hpp>
using std::cout;
using std::endl;
int main(){
float smallf = 100.1;
cout << (int)smallf << endl; // outputs 100 // c cast
cout << int(smallf) << endl; // outputs 100 // c++ constructor = c cast
cout << static_cast<int>(smallf) << endl; // outputs 100
// cout << static_cast<int&>(smallf) << endl; // not allowed
cout << reinterpret_cast<int&>(smallf) << endl; // outputs 1120416563
cout << boost::numeric_cast<int>(smallf) << endl; // outputs 100
float bigf = 1.23e12;
cout << (int)bigf << endl; // outputs -2147483648
cout << int(bigf) << endl; // outputs -2147483648
cout << static_cast<int>(bigf) << endl; // outputs -2147483648
// cout << static_cast<int&>(bigf) << endl; // not allowed
cout << reinterpret_cast<int&>(bigf) << endl; // outputs 1401893083
cout << boost::numeric_cast<int>(bigf) << endl; // throws bad numeric conversion
}
Hi I have a sample program
#include <iostream>
int main() {
int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
Here I am getting the output of 17179869164.
My question is that the array size value should not accept negative values! and if I try giving a[-5], it throws an error. but now how am I getting the output of 17179869164.
I have my assumption too, the -5 is converted to an unsigned int value of 4294967291 and the total size is given as 17179869164 = 4294967291 * 4(size of int).
So I wanted to know why the compiler is typecasting signed int to unsigned int and not throwing a compile-time error. I needed a clear understanding of how the compiler is executing that piece of code?
It is something called undefined behavior. To catch that kind of bug you could use the help of a static analyser.
Someone else asked something similar here:
Declaring an array of negative length
For C++, Variable Length Arrays are not provide by the standard, but may be provided by compiler extension. For C, the short answer is the standard converts the value to a positive integer value unless it is a constant expression -- in your case resulting in the use of the unsigned value (use of the two's compliment value as a positive value). Specifically:
C11 Standard - 6.7.6.2 Array
declarators(p5)
If the size is an expression that is not an integer constant
expression: if it occurs in a declaration at function prototype scope,
it is treated as if it were replaced by *; otherwise, each time it is
evaluated it shall have a value greater than zero.
I noticed some interesting behavior in GodBolt.
I took you code and added a second copy where a is declared constant:
#include <iostream>
int foo() {
int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
int bar() {
const int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
Then I threw GCC, Clang, and MSVC at them.
As far as I know, GCC and Clang both support variable length arrays (VLAs) as an "extra feature", and they both ate foo without a single complaint. Whereas MSVC, who does not support VLAs, complained.
On the other hand, none of them accepted bar on account of a being negative.
As for why GCC and Clang can't tell that ais negative in foo, that I will leave as a question for people more versed in compiler guts than I.
I have following code:
template <typename T>
struct wrapper {
T t;
operator T() { return t; }
T get() { return t; }
};
int main() {
int a[10];
int* x = a;
wrapper<long unsigned int> y{2};
std::cout << (x + y); // warning
}
When I compile it on gcc (tested on 7.3.0 and 8.2.0) with -Wsign-conversion I get "warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result". If y has type long unsigned int, there is no warning. Moreover when I explicitly call y.get() there is also no warning:
std::cout << (x + y.get()); // this is ok
Why this is the case? Are there some special rules for pointer arithmetic which cannot be used when using user-defined conversion?
Seems like a compiler issue/bug
(thanks #liliscent for correcting what I said here earlier)
First, let's make a single minimal reproducible example for all of the statement you were mentioning:
#include <iostream>
template <typename T>
struct wrapper {
T t;
operator T() const { return t; }
T get() const { return t; }
};
int main() {
int a[10];
int* x { a } ;
wrapper<long int> y1{2};
wrapper<unsigned int> y2{2};
wrapper<long unsigned int> y3{2};
std::cout << (x + y1) << '\n';
std::cout << (x + y2) << '\n';
std::cout << (x + y3) << '\n'; // this triggers a warning
std::cout << (x + y3.get()) << '\n';
}
and using GCC 8.2.0, we get:
<source>: In function 'int main()':
<source>:20:23: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion]
std::cout << (x + y3) << '\n';
^~
Compiler returned: 0
at the link, you will see how:
GCC emits this error with all (recent) versions.
Clang emits this error with version 6.0.
Clang does not emits this error with version 7.0.
So it must be some corner case w.r.t. standards compliance.
... but don't go into "Here Be Dragons" territory.
Now, I'm sure there's a complex technical explanation regarding why you only get an error on the 3rd of these streaming statements. But I claim it does not matter from a practical use perspective. If you stick to only adding proper integers to pointers - like you do with the .get() statement - you wouldn't get that warning.
You see, you are trying to add up a user-defined type to a pointer - which doesn't make much sense generally. It's true that your structure can be converted into an integer, but relying on this conversion to be made implicitly opens you up to things like the choice to convert the other operand, or other conversion paths you have not considered. What's more, these are cases in which you might 'hit' some esoteric clause in the standard regarding when implicit conversions are legit, which may or may not be implemented with perfect correctness by the compiler (see #cppcleaner's comment).
So just use x + y3.get() in your code and you'll not have to worry about these esoteric corner cases.
I have made a similar argument in this answer regarding the use of index 0 of an empty string (yes, that's a thing).
I was looking through stdlib.h within the include files for Dev-Cpp and I found a certain line:
#define _PTR_LD(x) ((unsigned char *)(&(x)->ld))
I then tried to use _PTR_LD in a program as follows:
class Thing {
public:
Thing();
int ld;
};
int main() {
Thing x;
x.ld = 8;
cout << _PTR_LD(x) << endl;
system("pause");
return 0;
}
I thought it would return the value for the attribute ld within x, but I got the following error message:
15 10 C:\Users\John\Desktop\Untitled1.cpp [Error] base operand of '->' has non-pointer type 'Thing'
I tried to search for _PTR_LD() but I found nothing about it. Does anyone know anything about _PTR_LD()?
What it does literally is take an expression that evaluates to a pointer, x, and returns a pointer to x->ld, reinterpreted as an unsigned char*.
What you're doing doesn't compile because -> has higher precedence than &, so your code evaluates to &(x->ld), which is invalid. If you instead printed the following:
x.ld = 'a';
std::cout << ( _PTR_LD(&x)) << std::endl;
then you'd see a printed, since you're reinterpreting &(x.ld) as a C-string, and that memory happens to look like the string {'a', 0}.
As to why this macro exists, I don't know. Does it matter? It's a reserved, internal-use macro.
I cannot find information about a behavior of sizeof (at least in gcc 4.6+). The following code works and produces the "expected" result (4, 1, 8), but I'm wondering why. I checked several questions but none show an example like this one.
#include<iostream>
int f1(int) {
return 0;
}
char f2(char) {
return 0;
}
double f3() {
return 0;
}
int main() {
std::cout << sizeof(f1(0)) << std::endl;
std::cout << sizeof(f2('0')) << std::endl;
std::cout << sizeof(f3()) << std::endl;
return 0;
}
An answer would be much appreciated.
Thanks.
The sizeof operator can take a type or an expression as an argument and returns the size of its argument. You're using expressions, so it returns the size of those expressions. The expression is not evaluated at run-time — so the functions are never invoked. But the correct (overloaded) function is used to determine the size of the result.
In a (now-deleted) comment, user1919074 said:
sizeof(f1) would not work
Brain fart
In C, sizeof(f1) would work since it would return the size of a pointer to function.
The sizeof() operator can't be applied direct to a function name. It has special rules, and when applied to an array, the normal 'decay' to a pointer doesn't occur. Similarly, the change of a function name to a function pointer doesn't occur with sizeof(). (Of course, you have to poke GCC hard with -pedantic to get it to give the warning/error; otherwise, it returns 1 as the size of the function.)
What is happening in the functions
int f1(int) {
return int(0);
}
char f1(char) {
return char(0);
}
double f1() {
return double(0);
}
What is happening later.
std::cout << sizeof(int(0)) << std::endl;
std::cout << sizeof(char('0')) << std::endl;
std::cout << sizeof(double(0)) << std::endl;
Because you are printing the sizeof the value of what is returned from the function
ISO/IEC 14882 on C++ says (section 5.3.3 - page 79):
says
"The size operator shall not be applied to an expression that has
function or incomplete type,..."
Also notice the compilation warning with the -pedantic option enabled...
warning: invalid application of 'sizeof' to a function type
f1 returns an integer which takes 4 bytes.
f2 returns a character which takes 1 byte.
f3 returns a double which takes 8 bytes.
So all sizeof() does is return the size of its argument.