PDA

View Full Version : Visual Studio and file I/O


Sir Penguin
30-11-2004, 07:40:11
I've written a function in C that writes a number of random bytes to a file. When I compile it with gcc, it works correctly. When I use Visual Studio, it writes a bunch of extra bytes (for n = 51200, it adds an extra 128 bytes, and for n = 5120 it adds an extra 17 bytes). I don't want to have to go back to gcc. Any ideas?

SP

Sir Penguin
30-11-2004, 07:40:43
Here's the test code:
#include <stdio.h>
#include <stdlib.h>
#define PASS_LEN 16
#define BLOCK_SIZE 512

void create_fs(FILE* newfile, int filesize, char* password)
{
int i; // iterator variable
int j;
int seed=0; // RNG seed
int written = 0;
int words[BLOCK_SIZE/sizeof(int)]; // array of random integers to write to file
/* write garbage to the file. */
for (i=0; i<=PASS_LEN; i++)
seed += password[i]*i;
srand(seed);
for (i=0; i<filesize/BLOCK_SIZE; i++) {
for (j=0; j<BLOCK_SIZE/sizeof(int); j++) {
words[j] = rand();
}
written += fwrite((void*)words,sizeof(int),BLOCK_SIZE/sizeof(int),newfile);
}
printf("Outer loop: %d\n",i);
printf("Inner loop: %d\n",j);
printf("Written: %d bytes\n",written*sizeof(int));
}

int main()
{
char buffer[1024];
FILE* newfile = fopen("file.txt","w");
fseek(newfile,0,SEEK_SET);
create_fs(newfile,51200,"thisisapassword_");
fclose(newfile);
fgets(buffer,1024,stdin);

}
The three printed lines (Outer loop, Inner loop, and Written) are correct using both compilers.

SP

Sir Penguin
30-11-2004, 07:44:23
Oh, also, Visual C++ seems to be writing two random bytes, then two space characters, then two random bytes, then two space characters, etc. gcc writes all random characters. :confused:

SP

Deacon
30-11-2004, 08:08:38
I dunno. Off the top of my head, maybe the type cast (void*) behaves differently in Windows.

MDA
30-11-2004, 12:42:38
Ask the cutest girl in class if she would mind "taking a look at your code".

Asher
30-11-2004, 15:27:51
I'm a bit busy to analyze it right now, but this is basically what my job is.

Our #1 peeve is customers saying "this works with gcc, and not your compiler -- fix it".

gcc sucks royal ass. 90% of the time, gcc is not conforming to standards and is actually generating incorrect output, while it may be something the programmer wanted in the first place, that's not always the case.

Whenever someone tells us "this works in gcc", we respond "that means absolutely nothing".

VC++ is far more standards compliant than gcc, so perhaps this is the issue...

Then again, you're still including the .h headers. Maybe you don't care for the modern standards. ;)

Asher
30-11-2004, 15:29:51
Also, is VC++ compiling this as a C++ program or as a C program...?

Sir Penguin
30-11-2004, 19:27:26
It should be a C program. If there was an option to choose between the two, then I selected it. I'd have to check back home to be sure.

Thing is, it has to compile on gcc, so that's what my baseline is. I'm only using Visual Studio because it's better. If it works on gcc, then it is proper code as far as I'm concerned.

I'm not saying that it's a bug in Visual Studio, clearly that would be stupid. But the behaviour somewhere in there isn't consistent with what I've learned.

SP

Asher
30-11-2004, 19:45:05
Check the value of sizeof(int) on both compilers, out of curiousity.

Asher
30-11-2004, 19:51:40
FWIW, this behaves as expected with IBM's XL C/C++ compilers -- but only when it's compiled as a CPP program. It's not a C program, due to the includes. :)

$ xlc canuck.cpp
$ ./a.out
Outer loop: 100
Inner loop: 128
Written: 51200 bytes
$ ls -l
total 120
-rwxr-xr-x 1 dmilford staff 7115 Nov 30 14:47 a.out
-rw-r----- 1 dmilford staff 923 Nov 30 14:45 canuck.cpp
-rw-r--r-- 1 dmilford staff 51200 Nov 30 14:47 file.txt

Sir Penguin
30-11-2004, 20:49:46
They're both 32 bits.

WTF? Aren't those #includes C? I've always used them, and so have my professors. What are you supposed to do in C?

SP

Asher
30-11-2004, 21:16:35
Try including <cstdio> in Visual C++ instead of <stdio.h>

Asher
30-11-2004, 21:17:27
Here's your program when compiled as a C program:
$ xlc -c canuck.c
"canuck.c", line 8.49: 1506-046 (S) Syntax error.
"canuck.c", line 8.52: 1506-045 (S) Undeclared identifier iterator.
"canuck.c", line 10.9: 1506-275 (S) Unexpected text 'int' encountered.
"canuck.c", line 10.49: 1506-046 (S) Syntax error.
"canuck.c", line 10.52: 1506-045 (S) Undeclared identifier RNG.
"canuck.c", line 12.9: 1506-275 (S) Unexpected text 'int' encountered.
"canuck.c", line 12.49: 1506-046 (S) Syntax error.
"canuck.c", line 18.22: 1506-045 (S) Undeclared identifier j.
"canuck.c", line 21.17: 1506-045 (S) Undeclared identifier written.
"canuck.c", line 21.17: 1506-045 (S) Undeclared identifier written.

Asher
30-11-2004, 21:21:47
Some more information and a correction: It's not a valid C89 or ANSI C program, but it is a valid C99 program:
$ xlc -qlanglvl=stdc99 canuck.c
$ ./a.out
Outer loop: 100
Inner loop: 128
Written: 51200 bytes
$

Asher
30-11-2004, 21:25:12
another thing to try is to open the file in raw/binary write mode:
FILE* newfile = fopen("file.txt","wb");I think Windows is adding its carriage return automagically in there for you.

Darkstar
30-11-2004, 21:57:06
First off, I've got


warning C4267: '+=' : conversion from 'size_t' to 'int', possible loss of data


While building this...

Asher
30-11-2004, 21:59:45
Are you building it in 64-bit land?

Asher
30-11-2004, 22:00:56
size_t is 64-bit in Win64, int is still 32-bit.

Darkstar
30-11-2004, 22:01:22
Ok...

Under VS 2003, under a windows 32 console app...


#include "stdafx.h"


#include <stdio.h>
#include <stdlib.h>
#define PASS_LEN 16
#define BLOCK_SIZE 512


void create_fs(FILE* newfile, int filesize, char* password)
{
int i; // iterator variable
int j;
int seed=0; // RNG seed
int written = 0;
int words[BLOCK_SIZE/sizeof(int)]; // array of random integers to write to file
/* write garbage to the file. */
for (i=0; i<=PASS_LEN; i++)
seed += password[i]*i;
srand(seed);
for (i=0; i<filesize/BLOCK_SIZE; i++) {
for (j=0; j<BLOCK_SIZE/sizeof(int); j++) {
words[j] = rand();
}
written += fwrite((void*)words,sizeof(int),BLOCK_SIZE/sizeof(int),newfile);
}
printf("Outer loop: %d\n",i);
printf("Inner loop: %d\n",j);
printf("Written: %d bytes\n",written*sizeof(int));
}



int _tmain(int argc, _TCHAR* argv[])
{
char buffer[1024];
FILE* newfile = fopen("file.txt","w");
fseek(newfile,0,SEEK_SET);
create_fs(newfile,51200,"thisisapassword_");
fclose(newfile);
fgets(buffer,1024,stdin);

return 0;
}


Works fine with the following output:


Outer loop: 100
Inner loop: 128
Written: 51200 bytes


So... time to pop it over to your settings and see what it is doing...

Asher
30-11-2004, 22:02:14
Is the actual filesize 51200 bytes exactly?

The text output was always correct, if I understand correctly, but the file output itself was larger.

Darkstar
30-11-2004, 22:19:46
Alright, as a simple C program using the basic makefile...


Outer loop: 100
Inner loop: 128
Written: 51200 bytes


Sorry, Sir Penguin. I cannot duplicate your trouble.

Hey... you aren't counting the load of padding at the end of the file that is just on the disk as output from your file, are you? Humm...

Darkstar
30-11-2004, 22:22:07
For instance:


size on disk: 50.5 KB (51,712 bytes)


You realize that by clusters, you end up with a bit of extra at the end of the file, jah?

Sir Penguin
01-12-2004, 01:30:51
Yes, I'm looking at the actual filesize.

Asher, you were right about the newline thing. Opening the file as "wb" instead of "w" corrected the problem. I've been developing on UNIX too much. :)

Thanks a lot to both of you for the help. I'm glad I can keep using Visual Studio.

Incidentally, #including <cstdio> instead of <stdio.h> caused over 100 syntax errors dealing with ":" and "{" characters. I guess it didn't like the C++ stuff.

SP

Asher
01-12-2004, 01:42:38
You could've always used Visual C++ with GCC if you wanted. ;)

Darkstar
01-12-2004, 04:57:51
Hey, no problem, Sir Penguin.