Is it ANSI or is it compiler dependent?

  • Thread starter Canonical Latin
  • Start date
C

Canonical Latin

#include<iostream>
int main() {
char buff[3];
std::cin.getline(buff,3);
std::cin.getline(buff,3);
std::cout << buff << endl;
}
Run at command prompt and input
1234567
what do you get as output?
Please include your compiler make/version in replies.

The question is: Does ANSI require that ios::failbit to be set after
the first getline() or is it compiler dependent? I expect the output
to be an empty line. I'm particularly interested in complilers that
output '34'.

Thanks in advance
 
L

Leor Zolman

#include<iostream>
int main() {
char buff[3];
std::cin.getline(buff,3);
std::cin.getline(buff,3);
std::cout << buff << endl;

std::cout << buff << std::endl;
}
Run at command prompt and input
1234567
what do you get as output?
Please include your compiler make/version in replies.

The question is: Does ANSI require that ios::failbit to be set after
the first getline() or is it compiler dependent? I expect the output
to be an empty line. I'm particularly interested in complilers that
output '34'.

Thanks in advance

Some data points for you:

Comeau/libcomo: 12
Comeau/Dinkumware: (empty line)
MSVC7.1: (empty line)
MSVC6: (empty line)
MSVC6/Dinkumware: (empty line)
CodeWarrior 8: (empty line)
Borland 5.5.1: (empty line)
Borland C++BuilderX: 12
gcc 3.3: (empty line)
Digital Mars: 12
Intel 7/8: (empty line)

I expected "12". Section 27.6.1.3/17 does say that failbit will be set if
the buffer fills up before the trailing delimiter is detected. The output
is consistently 12 if you take away the second getline call, so perhaps
this really boils down to how the different versions of getline behave if
they're called with failbit already set. I suspect they're not obliged to
do any particular thing then, but I haven't located evidence of that in the
Standard yet.
-leor
 
C

Canonical Latin

Leor Zolman said:
Some data points for you:

Comeau/libcomo: 12
Comeau/Dinkumware: (empty line)
MSVC7.1: (empty line)
MSVC6: (empty line)
MSVC6/Dinkumware: (empty line)
CodeWarrior 8: (empty line)
Borland 5.5.1: (empty line)
Borland C++BuilderX: 12
gcc 3.3: (empty line)
Digital Mars: 12
Intel 7/8: (empty line)

I expected "12". Section 27.6.1.3/17 does say that failbit will be set if
the buffer fills up before the trailing delimiter is detected. The output
is consistently 12 if you take away the second getline call, so perhaps
this really boils down to how the different versions of getline behave if
they're called with failbit already set. I suspect they're not obliged to
do any particular thing then, but I haven't located evidence of that in the
Standard yet.
-leor



Thank you. I know this must've come up before, but if you may solve another
mystery for me



#include<iostream>

void fun(int v[2]) {

std::cout << sizeof(v) << endl; // sizeof(int*) = But this v is not a
type!

}

int main() {

int v[3]={};

std::cout << sizeof(v) << '-'; // 3 * sizeof(int) = OK v is a type.

fun(v);

}



under gcc 3.2 on a 32 bit data/memory machine I get: 12-4

Why does this even compile? Does ANSI say that typed array arg's are to be
ignored?
 
C

Canonical Latin

Canonical Latin said:
#include<iostream>
int main() {
char buff[3];
std::cin.getline(buff,3);
std::cin.getline(buff,3);
std::cout << buff << endl;
}
Run at command prompt and input
1234567
what do you get as output?
Please include your compiler make/version in replies.

I expect the output to be an empty line.

The reason I think it is reasonable for buff[0]='\0' after the second
getline() is that then the character count is zero indicating that nothing
was read. This behavior is backward compatible with C getlen().
 
L

Leor Zolman

Leor Zolman said:
Some data points for you:

Comeau/libcomo: 12
Comeau/Dinkumware: (empty line)
MSVC7.1: (empty line)
MSVC6: (empty line)
MSVC6/Dinkumware: (empty line)
CodeWarrior 8: (empty line)
Borland 5.5.1: (empty line)
Borland C++BuilderX: 12
gcc 3.3: (empty line)
Digital Mars: 12
Intel 7/8: (empty line)

I expected "12". Section 27.6.1.3/17 does say that failbit will be set if
the buffer fills up before the trailing delimiter is detected. The output
is consistently 12 if you take away the second getline call, so perhaps
this really boils down to how the different versions of getline behave if
they're called with failbit already set. I suspect they're not obliged to
do any particular thing then, but I haven't located evidence of that in the
Standard yet.
-leor



Thank you. I know this must've come up before, but if you may solve another
mystery for me



#include<iostream>

void fun(int v[2]) {

std::cout << sizeof(v) << endl; // sizeof(int*) = But this v is not a
type!

First of all, it didn't compile, because again you neglected to put std::
in front of endl.

Once that's fixed...what do you mean when you say "v is not a type"? Of
course it isn't, it is the name of some data. Just as it is below in
main(). In both cases you're asking what the storage is of the object
referred to by the name "v". Above it is a pointer to int, as you've
indicated, and below it is an array of 3 ints. Recall there are two forms
of sizeof:
sizeof expression
sizeof (type)
(And it is OK to put the expression in parens, if you prefer, but it is not
OK to leave out the parens in the 2nd case). You've used the first form in
both cases.

If you still have a question, let us know...
-leor
}

int main() {

int v[3]={};

std::cout << sizeof(v) << '-'; // 3 * sizeof(int) = OK v is a type.

fun(v);

}



under gcc 3.2 on a 32 bit data/memory machine I get: 12-4

Why does this even compile? Does ANSI say that typed array arg's are to be
ignored?
 
L

Leor Zolman

Canonical Latin said:
#include<iostream>
int main() {
char buff[3];
std::cin.getline(buff,3);
std::cin.getline(buff,3);
std::cout << buff << endl;
}
Run at command prompt and input
1234567
what do you get as output?
Please include your compiler make/version in replies.

I expect the output to be an empty line.

The reason I think it is reasonable for buff[0]='\0' after the second
getline() is that then the character count is zero indicating that nothing
was read. This behavior is backward compatible with C getlen().

Unfortunately (or fortunately, depending upon your point of view),
reasonability doesn't necessarily count for much. It seems just as
"reasonable" to me for getline to do absolutely nothing if failbit is
already set as it is for it to put a NUL into the first position of the
buffer. Well, in fact it actually seems a bit /more/ reasonable for it to
do nothing, for consistency with the way extractors don't alter their
operand if the stream is broken;
cin >> i; // doesn't alter i if it can't extract

BTW, what the heck is "C getlen()" ?
-leor
 
N

none

Canonical Latin wrote:> ...
#include<iostream>

void fun(int v[2]) {

std::cout << sizeof(v) << endl; // sizeof(int*)

Yes, it shall output size of 'int*', since declaration 'int v[2]' is
equivalent to 'int* v' in this context.
But this v is not a type!

Huh? So what? 'sizeof' works with expressions just like it works with types.
int main() {

int v[3]={};

std::cout << sizeof(v) << '-'; // 3 * sizeof(int)

As expected.
OK v is a type.

No, 'v' is a name of an object of array type.
fun(v);

}



under gcc 3.2 on a 32 bit data/memory machine I get: 12-4

Why does this even compile?

Why shouldn't it compile?
Does ANSI say that typed array arg's are to be
ignored?

ANSI says that function parameters of array type are automatically
replaced with parameters of pointer type.
 
L

Leor Zolman

LOL. A simple "I don't know" would have been shorter

I was in fact trying to answer the question. The way you used the word
"type", however, led me to believe I needed to clarify the distinction
between type and object in the context of using the sizeof operator. If
that in itself didn't answer your question, I was inviting you to rephrase
it so I could understand what you meant. In what way would "I don't know"
have been a better answer?
-leor
 
C

Canonical Latin

Leor Zolman said:
I was in fact trying to answer the question. The way you used the word
"type", however, led me to believe I needed to clarify the distinction
between type and object in the context of using the sizeof operator. If
that in itself didn't answer your question, I was inviting you to rephrase
it so I could understand what you meant.

Sorry. I had assumed the use of word 'type' was clear in the context of my
question. But here is a more carefully 'worded' version.

int v[3];
int w[3][3];

Granted that v is a variable with certain storage type. But v is also a
variable of type int[3] and w is a of type int[3][3].

void fun1(int v[2]) {}
void fun2(int v[2][3]) {}
void fun3(int v[2][2]) {}
int main() {
int v[3]={};
int w[3][3]={};
fun1(v);
fun2(w);
fun3(w);
}

It is a mystery to me why fun3(w) produces a compile error while the others
don't. For some reason the first dimension of an array is ignored when doing
type checking--as if v had the type int[] and w the type int[][3]. I used
sizeof operator to note that indeed v has the same storage requirement as
type int[2] in the main() which implies that at least here the compiler
acknowledges that v is indeed of type int[2] and not of type int[]. But then
later it treats it as int[] despite the specified type.

You can also check this by noting that fun(int v[3]) and fun(int v[4])
cannot be overloaded (since the compiler sees them as type int[]) but the
fun(int v[3][3]) and fun(int v[4][4]) can be overloaded.

I realize that you don't need the size of the first dimension of an array
for index computation while you need the rest. But surely this is a
different issue than type checking.
 
L

Leor Zolman

Sorry. I had assumed the use of word 'type' was clear in the context of my
question. But here is a more carefully 'worded' version.

I tend to take wording pretty literally, because often ambiguous wording
reflects a poster's unfamiliarity with the basic concepts--so I can't be
quite sure if the question I think I'm answering is the one really being
asked. I, in fact, often answer the wrong question even when the wording is
/clear/, so I tend to ask for clarification a lot ;-)
int v[3];
int w[3][3];

Granted that v is a variable with certain storage type. But v is also a
variable of type int[3] and w is a of type int[3][3].

OK, I'm already hung up on your wording above. In this case it isn't going
to keep me from answering you subsequent questions, but... what do you mean
by v being "a variable with certain storage type", and "also a variable of
type int[3]" ? Isn't int[3] in fact "a certain storage type"? I'm sorry,
this is a really strange way to phrase whatever it is you're thinking, and
I must admit I haven't a clue as to what you are trying to say. But
hopefully it won't matter, if you understand what's going on below.
void fun1(int v[2]) {}
void fun2(int v[2][3]) {}
void fun3(int v[2][2]) {}
int main() {
int v[3]={};
int w[3][3]={};

Are the empty braces just to force zero-initialization? I didn't even
realize that was legal, until just trying it. Usually I see at least a 0
in there, e.g:
int v[] = {0};
But I guess that's just a matter of style.
fun1(v);
fun2(w);
fun3(w);
}

It is a mystery to me why fun3(w) produces a compile error while the others
don't. For some reason the first dimension of an array is ignored when doing
type checking--as if v had the type int[] and w the type int[][3].

Formal parameters to a function written in the form of 1- or 2-dimensional
arrays actually do behave as you've just described, but they're actually
just pointers. Another way of looking at it: the first dimension of an
array parameter is "syntactic sugar", and is not actually part of the type.
The other dimensions are. In your definition of fun1 above, v has type
"pointer to int". In fun2, v has type "pointer to array of 3 ints". In
fun3, "pointer to array of 2 ints".

So let's look at your calls. In the call to fun1, you pass an array of int;
Arrays of T "decay" to type "pointer to T" when used in most contexts. So
you're actually passing a pointer to int, matching the parameter to fun1
fine.

In the call to fun2, you're passing w, a 2D array of ints with dims 3,3, or
alternatively, an array of 3 arrays of 3 ints. When you pass that to a
function, then, you're actually passing a pointer to an array of 3 ints.
Again a perfect match.

In the call to fun3, you're passing the same array, but this time to a
function expecting a different kind of pointer. Hence the error.
I used
sizeof operator to note that indeed v has the same storage requirement as
type int[2] in the main() which implies that at least here the compiler
acknowledges that v is indeed of type int[2] and not of type int[]. But then
later it treats it as int[] despite the specified type.

Okay, I've lost you again. You've defined v in main() as follows:
int v[3]={};
That's type int[3]; not type int[2], and certainly not int[] -- which isn't
even really a type, and you can test that by trying to compile a line like
this:
cout << "size: " << sizeof(int[]) << endl;
and noting it does not compile. Remember, when used in a formal parameter
declaration, it is really treated as "int *".
You can also check this by noting that fun(int v[3]) and fun(int v[4])
cannot be overloaded (since the compiler sees them as type int[])

which is the same as "int *"...
but the
fun(int v[3][3]) and fun(int v[4][4]) can be overloaded.

Right. Different types.
I realize that you don't need the size of the first dimension of an array
for index computation while you need the rest. But surely this is a
different issue than type checking.

Bzzzt. All but the first dimension of an array parameter are crucial to the
type; hence, crucial to type-/checking/.
-leor
 
C

Canonical Latin

Leor Zolman said:
I tend to take wording pretty literally, because often ambiguous wording
....
Bzzzt. All but the first dimension of an array parameter are crucial to the
type; hence, crucial to type-/checking/.

I'm sorry that you can't understand me. I still thank you for your reply to
my original question but ask for no further assistance as I can't understand
your subsequent replies either. I still consider the second question
unanswered if someone else may have an idea.



The question is:



Why in ANSI c++ the first dimension of an array is ignored in its type name
in the examples that I gave (e.g overloading a function).
 
R

Rob Williscroft

Canonical Latin wrote in
in comp.lang.c++:
Why in ANSI c++ the first dimension of an array is ignored in its type
name in the examples that I gave (e.g overloading a function).

Because in C++ (and also C) you can't pass around array's.
The language handles arrays by /decaying/ them to pointers.
So a function such as:

int f( int a[3] );

is really:

int f( int *a );

Again:

int g( int b[3][2] );

is really:

int g( int (*b)[2] );

or (for typedef fans):

typedef two_ints[2];

int g( two_ints *b );


As to "Why ?", well that was how C was designed to work and C++
"inherited" the behaviour. "Why ?" doesn't actually matter, its
the way it is and we have to live with it.

Rob.
 
D

Dave Moore

Canonical Latin said:
Sorry. I had assumed the use of word 'type' was clear in the context of my
question. But here is a more carefully 'worded' version.

When passed to functions, 1-D arrays are converted to pointers, and
n-dimension arrays are converted to pointers to n-1 dimension arrays.
Thus, for determining the type of the argument, it is the converted
value that is used.

Using your examples (with my comments)
void fun1(int v[2]) {} // equivalent to void fun1(int *v) {}

So it will work with any 1-D array or int pointer.
void fun2(int v[2][3]) {} // equivalent to void fun2(int *v[3]) {}
void fun3(int v[2][2]) {} // equivalent to void fun3(int *v[2]) {}

int main() {
int v[3]={};
int w[3][3]={};
fun1(v); // ok, converted type of argument is int *
fun2(w); // ok, converted type of argument is int *[3]
fun3(w); // error, conv.type of arg. is int *[3], expcecting int *[2]
}

See Stroustrup TC++PL section C.7 for more info, and also sections
4.2, 8.3.4 and 13.1 of the Standard.

HTH, Dave Moore
 
L

Leor Zolman

I'm sorry that you can't understand me. I still thank you for your reply to
my original question but ask for no further assistance as I can't understand
your subsequent replies either. I still consider the second question
unanswered if someone else may have an idea.

Darn, and I thought I did such a good job on that last one! Perhaps when
you put Rob's code and words alongside my longer-winded analysis, the
combination will make some sense ;-)
Good luck,
-leor
 
O

Old Wolf

Canonical Latin said:
It is a mystery to me why fun3(w) produces a compile error while the others
don't. For some reason the first dimension of an array is ignored when doing
type checking--as if v had the type int[] and w the type int[][3].

You cannot pass arrays to functions. You cannot declare a function that
takes an array as parameter (if you try, then what you are actually
declaring a function that takes a pointer to the first parameter of
that array). Finally, if you use an array name in a value context
(eg. as an argument in a function call), it gets converted to a pointer
to that array's first member.

You have observed that this conversion loses information: namely, the
number of elements in the array.
void fun1(int v[2]) {}

v[0] has type "int", so this is identical to:
void fun1(int *v) {}
void fun2(int v[2][3]) {}

v[0] has type "int [3]", so :
void fun2(int (*v)[3]) {}
void fun3(int v[2][2]) {}

void fun3(int (*v)[2]);

Some people prefer to always write the versions with "*",
to avoid confusion.
int main() {
int v[3]={};

v has type "int [3]"
int w[3][3]={};

w has type "int [3][3]"

When using an array when a value is expected, the array is converted to
a pointer to its first element. v[0] has type "int", so &v[0] has
type "int *". Since fun1 is "void fun1(int *)", this is OK.

w[0] has type "int [3]" . &w[0] has type "int (*)[3]".
fun2 is "void fun2(int (*)[3])". So this is OK too.

&w[0] has type "int (*)[3]". But fun3 has type "void fun3(int (*)[2])".
So this is not OK. A set of rows (each containing 3 ints) cannot be
substituted for a set of rows (each containing 2 ints).

In case you were unaware, you could pass a pointer to the entire array
to a function:

void fun4(int (*v)[3][3]); // or: void fun4(int v[1][3][3])

int x[3][3];
fun4(&x);
 
T

tom_usenet

Canonical Latin said:
#include<iostream>
int main() {
char buff[3];
std::cin.getline(buff,3);
std::cin.getline(buff,3);
std::cout << buff << endl;
}
Run at command prompt and input
1234567
what do you get as output?
Please include your compiler make/version in replies.

I expect the output to be an empty line.

The reason I think it is reasonable for buff[0]='\0' after the second
getline() is that then the character count is zero indicating that nothing
was read. This behavior is backward compatible with C getlen().

The standard is currently ambiguous on this point (what getline should
do for a non-good stream), but there is a defect about it
(http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#243)
which resolves it to behave as you want. Dinkumware's library already
does it that way apparently.

Tom
 
C

Canonical Latin

tom_usenet said:
The standard is currently ambiguous on this point (what getline should
do for a non-good stream), but there is a defect about it
(http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#243)
which resolves it to behave as you want. Dinkumware's library already
does it that way apparently.

Tom

Thank you that is a great reference. That link answers a lot of the
questions that I've had and a great many that I've not even asked yet. But
I'm still curious as to the rational of having type
pointer-to-array-of-size-N-of-type-T (which is fine) and not having type
array-of-size-N-of-type-T (with some exceptions, which is curious). So far
the consensus seems to be that while everyone is aware of this no one knows
the rational behind it. I'm sure there must be a compelling reason for this
and once explained it would be obvious :)
 
L

Leor Zolman

Thank you that is a great reference. That link answers a lot of the
questions that I've had and a great many that I've not even asked yet. But
I'm still curious as to the rational of having type
pointer-to-array-of-size-N-of-type-T (which is fine) and not having type
array-of-size-N-of-type-T (with some exceptions, which is curious).

I know you asked me not to answer any more of your questions, but I'm
stubborn ;-)

The place where you can't have array-of-size-N is in the special case of a
function parameter. Otherwise they're fine.

In the case of function parameters, if an array got passed by value, that
would be a very expensive operation. Most of the time folks would have to
program around it, by writing an expression that evaluates to a pointer of
some kind and passing /that/. But believe it or not, if arrays got passed
by value, that would actually be the special case...because of the
following:

As I'm fond of saying, arrays are just "smoke and mirrors" anyway; they're
mostly syntactic sugar, and compilers translate array names into pointers
to their first elements (there are a few exceptions, such as when applying
sizeof). That's true even if you don't pass them to a function.

So, given:
int a[10];
a[3] = 5;

that last line actually compiles into something like:
*(&a[0] + 3) = 5;

Therefore, in a function call such as:
func(a);

it makes perfect sense what gets passed is a pointer to the first element
of the array:

func(&a[0]);

and thus there's no information available to the function about the size of
that array.
-leor
 
C

Canonical Latin

Leor Zolman said:
Thank you that is a great reference. That link answers a lot of the
questions that I've had and a great many that I've not even asked yet. But
I'm still curious as to the rational of having type
pointer-to-array-of-size-N-of-type-T (which is fine) and not having type
array-of-size-N-of-type-T (with some exceptions, which is curious).

I know you asked me not to answer any more of your questions, but I'm
stubborn ;-)

The place where you can't have array-of-size-N is in the special case of a
function parameter. Otherwise they're fine.

In the case of function parameters, if an array got passed by value, that
would be a very expensive operation. Most of the time folks would have to
program around it, by writing an expression that evaluates to a pointer of
some kind and passing /that/. But believe it or not, if arrays got passed
by value, that would actually be the special case...because of the
following:

As I'm fond of saying, arrays are just "smoke and mirrors" anyway; they're
mostly syntactic sugar, and compilers translate array names into pointers
to their first elements (there are a few exceptions, such as when applying
sizeof). That's true even if you don't pass them to a function.

So, given:
int a[10];
a[3] = 5;

that last line actually compiles into something like:
*(&a[0] + 3) = 5;

Therefore, in a function call such as:
func(a);

it makes perfect sense what gets passed is a pointer to the first element
of the array:

func(&a[0]);

and thus there's no information available to the function about the size of
that array.
-leor




So far
the consensus seems to be that while everyone is aware of this no one knows
the rational behind it. I'm sure there must be a compelling reason for this
and once explained it would be obvious :)

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html

As this thread seems to be about an entirely different issue than the
original question, I have started a new thread
"Typed arrays (was: Is it ANSI or is it compiler dependent?)"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top