[c++] get() and read() functions.

Z

ZikO

Hi.

Im using C++ Compiler as below:
g++ (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502
Copyright (C) 2008 Free Software Foundation, Inc.

Im writing the simple program which is supposed to give info about sound
wave file. It checks whether a file is a wave format (4 ASCII bytes
should be like {'R','I','F','F'}) and then it reads what the size of the
file is (another 4 bytes). However, I found difficult to understand how
to use both get() and read() functions properly which are in <fstream>
library.

there is the code below in which I check if file starts with "RIFF". I
have used waveFile.get() function to obtain 4 bytes from the input
stream, although I wanted read() before. I had to use get() because if I
used read() instead the program would go straight to else branch and
display "This is not a wave file", even if it is.

Any suggestions why read() does not work here?

Thanks.



PS. The test file can be found here:
http://rapidshare.de/files/44749739/test.wav.html

Code:
..ifstream waveFile("test.txt");
..int filePointer = 0;
..  char temp[5] = {0,0,0,0};
..  if(waveFile.get(temp,4)) {
..    // cout << "stream pointer = " << waveFile.tellg() << endl;
..    filePointer += 4;
..    char waveChunk[] = {"RIFF"};
..    if(strcmp(temp, waveChunk)) {
..      cout << "This is a wave file." << endl;
..    }
..    else {
..      cout << "This is not a wave file" << endl;
..      return 0;
..    }
..  }
..  else
..    checkStream(waveFile);
..
..  int roz;
..  waveFile.seekg(filePointer);
..  if(waveFile.read(reinterpret_cast<char*>(&roz), 4)) {
..    filePointer += 4;
..    roz += 8;
..    cout << "The size is: " << roz << endl;
..  }
..  else
..  checkStream(waveFile);
 
Z

ZikO

Victor said:
That's not necessarily important here. Unless you suspect it's a bug in
the compiler or the standard library that comes with it, they all should
be essentially the same.

I thought it would be important which compiler I use as I do not know
about bugs which might be already in it.
Why are you sure that it "does not work"?

Try looking at the 'temp' buffer. Print it out, char by char. Are you
sure you get 'R', 'I', 'F', 'F' in it? Could it be 'F', 'F', 'I', 'R'?
Anyway, what does your favourite C++ book say about the behaviour of
this particular 'get'? What if you fill your array char by char, as in

temp[0] = waveFile.get();
temp[1] = waveFile.get();
temp[2] = waveFile.get();
temp[3] = waveFile.get();

?
After using read() both strings are eual in number of characters +
termination char and contain the same string "RIFF".
1) I found problem with get() function which read only 3 chars ;/ even
if specified to read 4 of them; what a mess.
2) It seems like strcmp() is broekn in it :///. it showed that ("RIF" ==
"RIFF" = true). that's surprise.

After I have written my own function comparing strings, everything
starts working properly.

Regards.
 
K

Kaz Kylheku

PS. The test file can be found here:
http://rapidshare.de/files/44749739/test.wav.html

Code:
.ifstream waveFile("test.txt");[/QUOTE]

I can't find anywhere in your code where you told this waveFile
object that the file is binary.
[QUOTE]
.int filePointer = 0;
.  char temp[5] = {0,0,0,0};
.  if(waveFile.get(temp,4)) {
.    // cout << "stream pointer = " << waveFile.tellg() << endl;
.    filePointer += 4;
.    char waveChunk[] = {"RIFF"};
.    if(strcmp(temp, waveChunk)) {[/QUOTE]

temp and waveChunk are not null-terminated strings; you can't
compare them with strcmp. Look up memcmp in your reference manual.

Your test for file type is therefore unreliable.
[QUOTE]
.      cout << "This is a wave file." << endl;
.    }
.    else {
.      cout << "This is not a wave file" << endl;
.      return 0;
.    }
.  }
.  else
.    checkStream(waveFile);
.
.  int roz;
.  waveFile.seekg(filePointer);
.  if(waveFile.read(reinterpret_cast<char*>(&roz), 4)) {[/QUOTE]

You have some bad portability assumptions here, like that the size of integer
is four, and that an integer in the wave file has the same representation as
this native integer, using the same byte order.
 
T

Thomas J. Gritzan

ZikO said:
After using read() both strings are eual in number of characters +
termination char and contain the same string "RIFF".
1) I found problem with get() function which read only 3 chars ;/ even
if specified to read 4 of them; what a mess.
2) It seems like strcmp() is broekn in it :///. it showed that ("RIF" ==
"RIFF" = true). that's surprise.

How do you use strcmp?
After I have written my own function comparing strings, everything
starts working properly.

But you are aware, that strcmp returns 0 if the strings are equal?
 
E

Erik Wikström

Victor said:
That's not necessarily important here. Unless you suspect it's a bug in
the compiler or the standard library that comes with it, they all should
be essentially the same.

I thought it would be important which compiler I use as I do not know
about bugs which might be already in it.
Why are you sure that it "does not work"?

Try looking at the 'temp' buffer. Print it out, char by char. Are you
sure you get 'R', 'I', 'F', 'F' in it? Could it be 'F', 'F', 'I', 'R'?
Anyway, what does your favourite C++ book say about the behaviour of
this particular 'get'? What if you fill your array char by char, as in

temp[0] = waveFile.get();
temp[1] = waveFile.get();
temp[2] = waveFile.get();
temp[3] = waveFile.get();

?
After using read() both strings are eual in number of characters +
termination char and contain the same string "RIFF".
1) I found problem with get() function which read only 3 chars ;/ even
if specified to read 4 of them; what a mess.

Read will real one character less that you specify and put \0 in the
last location. In other words you don't specify how many characters it
should read but how many characters (including the \0) you can fit into
the array.
 
J

Juha Nieminen

Victor said:
.ifstream waveFile("test.txt");
.int filePointer = 0;
. char temp[5] = {0,0,0,0};
. if(waveFile.get(temp,4)) {

Try looking at the 'temp' buffer. Print it out, char by char. Are you
sure you get 'R', 'I', 'F', 'F' in it? Could it be 'F', 'F', 'I', 'R'?

Why would std::ifstream::get() read 4 bytes from the stream, store
them into the given buffer, and then reverse the buffer? Why would that
make any sense?

The only possibility for the buffer to have "FFIR" is if that's what
was in the input file.
 
J

Juha Nieminen

ZikO said:
. char waveChunk[] = {"RIFF"};

I didn't even know this was valid. Does that even compile?

At least I read that as: A char array initialized with a list
containing one element: A const char pointer. My logic would dictate
that this must give a compiler error because you are trying to
initialize a char with a const char*, which are two completely different
types.
 
D

Default User

Juha said:
ZikO said:
. char waveChunk[] = {"RIFF"};

I didn't even know this was valid. Does that even compile?

At least I read that as: A char array initialized with a list
containing one element: A const char pointer. My logic would dictate
that this must give a compiler error because you are trying to
initialize a char with a const char*, which are two completely
different types.

As the Standard says:

8.5.2 Character arrays [dcl.init.string]
1 A char array (whether plain char, signed char, or unsigned char) can
be initialized by a string-literal (optionally enclosed in braces); a
wchar_t array can be initialized by a wide string-literal (optionally
enclosed in braces); successive characters of the string-literal
initialize the members of the array.




Brian
 
J

Juha Nieminen

Victor said:
Juha said:
ZikO said:
. char waveChunk[] = {"RIFF"};

I didn't even know this was valid. Does that even compile?

At least I read that as: A char array initialized with a list
containing one element: A const char pointer. My logic would dictate
that this must give a compiler error because you are trying to
initialize a char with a const char*, which are two completely different
types.

No, the compiler simply drops the superfluous curly braces. After that
it's an initialisation of a char array with a literal.

So does this cause a compiler error, then:

const char* table[] = {"RIFF"};

Or does the meaning of "{}" change depending on what's on the left
side of the '='? This is confusing. (And I thought I was fluent in C++...)

Seeing how the C++0x standard is going to enhance the meaning of {}
initialization lists, I hope it doesn't get even more confusing than it
already is...
 
Z

ZikO

Victor said:
In fact, the OP ought to use std::string
for his program, it would be so much easier:

std::string waveChunk("RIFF");
if (waveChunk == temp) //
>
V

I think i will start using string instead of old char. Thanks for
suggestion.

ZikO
 
Z

ZikO

Juha said:
ZikO said:
. char waveChunk[] = {"RIFF"};

I didn't even know this was valid. Does that even compile?

At least I read that as: A char array initialized with a list
containing one element: A const char pointer. My logic would dictate
that this must give a compiler error because you are trying to
initialize a char with a const char*, which are two completely different
types.
I dont know c++ rules as deeply as you but this line
.....char waveChunk[] = {"RIFF"};
should be the same as line
.....char waveChunk[] = {'R', 'I', 'F', 'F', '\0'};
which is the same as for int type
.....int intTable[] = {1, 2, 3, 3, 0};

You probably think about something else like:
.....const char* waveChunk = "RIFF";
which is also accepted by compilers.

If I type:
.....char wave[] = "aaa";
I get warning:
.....test.cpp: In function 'int main(int, char**)':
.....test.cpp:6: warning: deprecated conversion from string constant to
'char*'

I believe my 1st typic is simply correct.
 
Z

ZikO

Thomas said:
But you are aware, that strcmp returns 0 if the strings are equal?

No :p

I thought strcmp returns true. Oh mine. This is the problem. Thank you
very much. This is why i thought it's wrong. 0 - means, false, and
strcmp returns 0 when they are equal which is false. There is my
incorrect thinking. Thanks you
 
Z

ZikO

Thanks everyone for ur suggestions and answers =)

btw do u know any good reference to C++ library> Thanks you. I will also
look for it myself but maybe someone just provide the link faster than i
can find =))

Best regards to everyone
 
D

Default User

Juha said:
So does this cause a compiler error, then:

const char* table[] = {"RIFF"};

I'm not sure why you think so, but:

8.5.1 Aggregates [dcl.init.aggr]
1 An aggregate is an array or a class (clause 9) with no user-declared
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3).
2 When an aggregate is initialized the initializer can contain an
initializer-clause consisting of a braceenclosed, comma-separated list
of initializer-clauses for the members of the aggregate, written in
increasing subscript or member order.
4 An array of unknown size initialized with a brace-enclosed
initializer-list containing n initializers, where n shall be greater
than zero, is defined as having n elements.

Or does the meaning of "{}" change depending on what's on the left
side of the '='? This is confusing. (And I thought I was fluent in
C++...)

In the case of character arrays initialized with a string-literal, the
braces are optional.



Brian
 
D

Default User

ZikO said:
If I type:
....char wave[] = "aaa";
I get warning:
....test.cpp: In function 'int main(int, char**)':
....test.cpp:6: warning: deprecated conversion from string constant
to 'char*'

Are you sure? That shouldn't be the case. Perhaps you meant:


char *wave = "aaa";


That is legal, but deprecated, and not safe.



Brian
 
J

James Kanze

Victor said:
Juha said:
ZikO wrote:
. char waveChunk[] = {"RIFF"};
I didn't even know this was valid. Does that even compile?
At least I read that as: A char array initialized with a
list containing one element: A const char pointer. My logic
would dictate that this must give a compiler error because
you are trying to initialize a char with a const char*,
which are two completely different types.
No, the compiler simply drops the superfluous curly braces.
After that it's an initialisation of a char array with a
literal.
So does this cause a compiler error, then:
const char* table[] = {"RIFF"};

No. It defines an array of one char const*, initialized to
point to a staticly allocated char const[5] containing 'R', 'I',
'F', 'F', '\0'.
Or does the meaning of "{}" change depending on what's on the
left side of the '='? This is confusing. (And I thought I was
fluent in C++...)

The problem isn't really the meaning of the {}, what's changing
is the meaning of the string literal. When a string literal is
used to initialize an array of char (and only then), it has a
special meaning.
Seeing how the C++0x standard is going to enhance the meaning
of {} initialization lists, I hope it doesn't get even more
confusing than it already is...

The goal is to simplify things, by making them more orthogonal.
 

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

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top