gcc compiler

A

An

Hello,

I'm new to C and now I encountered the following problem.
When I compile the program hulp.c (the code is below) with the command
gcc -O -o hulp hulp.c,
running the program with input 1 2 3 4 1 2 3 4 1 2 3 4 1 2
gives output
12341234123412
00041234123412.
I don't understand how it is possible that the value of
macht[0],macht[1]and macht[2] don't remain 1 2 3.

It gets even more mysterious to me, since when I compile things using
gcc -o hulp hulp.c
running the program with the same input as above now gives the
expected output:
12341234123412
12341234123412.

How is this possible? What is the influence of the -O in the compiler
command? In the manual I read this has to do with optimization, but
what does it do here?

If I replace the type 'char' of 'inleeslg' to 'int', with the same
input as above BOTH compilers give the expected output:
12341234123412
12341234123412.
How can this be explained?

I really hope someone can help me out...

Here below one can find the code.
The first line of the file "facortest" is 2 1 1 2 3 4 5 6 7 8 9 10 11
0 .

Thank you in advance,

An


*********************************************************
#include <stdio.h>

main()
{FILE *fp;
short i;
char inleeslg;
char macht[14];
long pbas;
char e;

fp=fopen("Factortest","r");
if ((fp=fopen("Factortest","r"))==NULL) printf("Kan datafile niet
openen \n");
else{
printf("Type 14 small numbers:\n");
for(i=0;i<14;i++)
{scanf("%d",&macht);
}
/*Printing the input */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");

fscanf(fp,"%d %d %d",&pbas,&e,&inleeslg);

/*Printing the input again */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");
}
fclose(fp);
}
******************************************************************
 
A

Arthur J. O'Dwyer

I'm new to C and now I encountered the following problem.
When I compile the program hulp.c (the code is below) with the command
gcc -O -o hulp hulp.c,
running the program with input 1 2 3 4 1 2 3 4 1 2 3 4 1 2
gives output
12341234123412
00041234123412.
I don't understand how it is possible that the value of
macht[0],macht[1]and macht[2] don't remain 1 2 3.

You are overwriting them with zeroes, that's why. See below.

How is this possible? What is the influence of the -O in the compiler
command? In the manual I read this has to do with optimization, but
what does it do here?

It optimizes. Since your code was wrong to begin with, *any*
optimization is correct. So it makes some optimizations that change
the behavior of your program from wrong to wrong --- not a problem!
Write correct code, and suddenly the optimizer has a lot less leeway. :)

#include <stdio.h>

main()

int main(void) is preferred, and will work in C99 (the most recent
standardization).
{FILE *fp;
short i;
char inleeslg;
char macht[14];
long pbas;
char e;

fp=fopen("Factortest","r");
if ((fp=fopen("Factortest","r"))==NULL) printf("Kan datafile niet
openen \n");

Double whoops! First, you open the "Factortest" file *twice* here;
that's unwise, although I don't think it's a bug, strictly speaking.
The second problem is that your string literal overruns its line. Strings
in C can't span lines. Use a narrower margin for C code if necessary.

if (fp == NULL) printf("Kan datafile niet openen!\n");

else{
printf("Type 14 small numbers:\n");
for(i=0;i<14;i++)
{scanf("%d",&macht);


Here is a bug. 'macht' is an array of char, not int. "%d" is the
format specifier for int. You mean something like

{
int tmp;
scanf("%d", &tmp);
macht = tmp; /* with optional error-checking */
}
/*Printing the input */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");

fscanf(fp,"%d %d %d",&pbas,&e,&inleeslg);


Here is another bug. 'pbas' is a long int. 'e' and 'inleeslg' are
chars. None of them are ints, which is what fscanf("%d") is expecting.
The correct format specifier for 'long int' is "%ld"; the two chars
can be read in using the temporary-variable solution I gave you above.
/*Printing the input again */
for(i=0;i<14;i++)
{printf("%d",macht);


Note that this is *not* a bug, since while 'macht' is a char,
it is passed as an int to 'printf'. However, learning when it is
safe to rely on the integer promotions is a tricky business.
}
printf("\n");
}
fclose(fp);

And last but not least,

return 0;
 
J

Jens.Toerring

An said:
I'm new to C and now I encountered the following problem.
When I compile the program hulp.c (the code is below) with the command
gcc -O -o hulp hulp.c,
running the program with input 1 2 3 4 1 2 3 4 1 2 3 4 1 2
gives output
12341234123412
00041234123412.
I don't understand how it is possible that the value of
macht[0],macht[1]and macht[2] don't remain 1 2 3.
It gets even more mysterious to me, since when I compile things using
gcc -o hulp hulp.c
running the program with the same input as above now gives the
expected output:
12341234123412
12341234123412.
How is this possible? What is the influence of the -O in the compiler
command? In the manual I read this has to do with optimization, but
what does it do here?
char inleeslg;
char macht[14];
long pbas;
char e;

but later you have
fscanf(fp,"%d %d %d",&pbas,&e,&inleeslg);

You are promising the fscanf() function that all 'pbas', 'e and 'inlesslg'
are integers but they aren't. But fscanf() doesn't know that and, under
certain circumstances, it probably writes over the memory of some other
variable. It's spelled out in the "manual", but under a different heading
than you probably were looking for. You invoke so-called "undefined
behaviour" and then all bets are off. Your program can seem to work, it
can run but give wrong results, it can just crash or even reformat your
harddisk (luckily, that doesn't happen too often nowadays anymore;-). By
playing around wit the optimization options the resulting executables
will be slightly different and you see two of the above mentioned conse-
quences: in one case the program seems to work, in the other it also runs
but gives you some strange output.
If I replace the type 'char' of 'inleeslg' to 'int', with the same
input as above BOTH compilers give the expected output:
12341234123412
12341234123412.
How can this be explained?

Once you also have made 'pbas' and 'e' ints (or corrected the format
string you pass to fscanf()) your program does not invoke undefined
behaviour anymore and it will run perfectly well and give correct
results forever and a day.
#include <stdio.h>

Make that

int main()

or

int main( void )

otherwise you're going to get into trouble once you start using a
C99 compliant compiler.
printf("Type 14 small numbers:\n");
for(i=0;i<14;i++)
{scanf("%d",&macht);


Using scanf() to read in user input is basically impossible to get
right (just have the user make a typing error and the program will
blow up). Better look up e.g. fgets(), read in the whole line and
then disassemble it into the pieces you're looking for.

BTW, white space has become rather cheep so you are allowed to
use lots more of it for the indentation of your code, people
having to read it will be grateful...

Regards, Jens
 
E

Emmanuel Delahaye

In said:
When I compile the program hulp.c (the code is below) with the command
gcc -O -o hulp hulp.c,
running the program with input 1 2 3 4 1 2 3 4 1 2 3 4 1 2
gives output
12341234123412
00041234123412.
I don't understand how it is possible that the value of
macht[0],macht[1]and macht[2] don't remain 1 2 3.

It gets even more mysterious to me, since when I compile things using
gcc -o hulp hulp.c
running the program with the same input as above now gives the
expected output:
12341234123412
12341234123412.

Sounds like there is an Undefined Behaviour (UB) in your code.
How is this possible? What is the influence of the -O in the compiler
command? In the manual I read this has to do with optimization, but
what does it do here?

If I replace the type 'char' of 'inleeslg' to 'int', with the same
input as above BOTH compilers give the expected output:
12341234123412
12341234123412.
How can this be explained?

Typical UB. Anything can happen.
I really hope someone can help me out...

Here below one can find the code.
The first line of the file "facortest" is 2 1 1 2 3 4 5 6 7 8 9 10 11
0 .

*********************************************************
#include <stdio.h>

main()
{FILE *fp;
short i;
char inleeslg;
char macht[14];
long pbas;
char e;

fp=fopen("Factortest","r");
if ((fp=fopen("Factortest","r"))==NULL) printf("Kan datafile niet
openen \n");

Stop! UB. You can't open a file twice. The rest of the code is doomed.
else{
printf("Type 14 small numbers:\n");
for(i=0;i<14;i++)
{scanf("%d",&macht);


UB : "%d" expects the address of an int. You provided the address of a char.
}
/*Printing the input */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");

fscanf(fp,"%d %d %d",&pbas,&e,&inleeslg);


UB : "%d" expects the address of an int. You provided the address of a char,
an int and a long.
/*Printing the input again */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");
}
fclose(fp);
}
******************************************************************
 
O

Old Wolf

Emmanuel Delahaye said:
Stop! UB. You can't open a file twice. The rest of the code is doomed.

How is that UB? Most operating systems allow files to be open multiple
times for reading; I'd consider it a compiler defect if the first
fopen succeeded here but the second failed.
Anyhow, AFAIK the behaviour of fopen is implemetation-defined.
 
M

Mark McIntyre

How is that UB?

The standard says nothing about being able to associate two FILE stream
pointers with one file. Hence its UB.
Most operating systems allow files to be open multiple
times for reading;

That may be true.
AFAIK the behaviour of fopen is implemetation-defined.

For it to be IB, the Standard has to say so.
 
O

Old Wolf

Mark McIntyre said:
The standard says nothing about being able to associate two FILE stream
pointers with one file. Hence its UB.

Your argument is invalid: in the absence of a clause
specifically relating to opening two streams on one file, the assumption
must be that it is not undefined.

An analogy: it doesn't say you can simultaneously open a file called
"snarf" and a file called "foob" , so would it be UB if I tried that?

As it happens, we do have 7.19.2#8:
Whether the same file can be simultaneously open multiple
times is also implementation-defined.
For it to be IB, the Standard has to say so.

Dan Pop said so and, as a faithful minion, I didn't doubt :)
 
M

Mark McIntyre

Your argument is invalid: in the absence of a clause
specifically relating to opening two streams on one file, the assumption
must be that it is not undefined.

Consider the meaning of the word "undefined".
An analogy: it doesn't say you can simultaneously open a file called
"snarf" and a file called "foob" , so would it be UB if I tried that?

See above
As it happens, we do have 7.19.2#8:

Perhaps you meant 7.19.3#8. I do agree however that the last sentence of
this clause makes it IB.
Dan Pop said so and, as a faithful minion, I didn't doubt :)

Dan says lots of things. Not all of which are ISO C either .
 
A

An

Thanks a lot for all comments (from everyone)! I made some
adjustments acording to your comments, and everything works fine now
:). And, what's more important: I understand what I did wrong, so I
can avoid it from now on! The reason I tried to read the small
numbers in a "char", was to save memory. I have to learn about
'promotions'...

Thanks again,

An




Arthur J. O'Dwyer said:
I'm new to C and now I encountered the following problem.
When I compile the program hulp.c (the code is below) with the command
gcc -O -o hulp hulp.c,
running the program with input 1 2 3 4 1 2 3 4 1 2 3 4 1 2
gives output
12341234123412
00041234123412.
I don't understand how it is possible that the value of
macht[0],macht[1]and macht[2] don't remain 1 2 3.

You are overwriting them with zeroes, that's why. See below.

How is this possible? What is the influence of the -O in the compiler
command? In the manual I read this has to do with optimization, but
what does it do here?

It optimizes. Since your code was wrong to begin with, *any*
optimization is correct. So it makes some optimizations that change
the behavior of your program from wrong to wrong --- not a problem!
Write correct code, and suddenly the optimizer has a lot less leeway. :)

#include <stdio.h>

main()

int main(void) is preferred, and will work in C99 (the most recent
standardization).
{FILE *fp;
short i;
char inleeslg;
char macht[14];
long pbas;
char e;

fp=fopen("Factortest","r");
if ((fp=fopen("Factortest","r"))==NULL) printf("Kan datafile niet
openen \n");

Double whoops! First, you open the "Factortest" file *twice* here;
that's unwise, although I don't think it's a bug, strictly speaking.
The second problem is that your string literal overruns its line. Strings
in C can't span lines. Use a narrower margin for C code if necessary.

if (fp == NULL) printf("Kan datafile niet openen!\n");

else{
printf("Type 14 small numbers:\n");
for(i=0;i<14;i++)
{scanf("%d",&macht);


Here is a bug. 'macht' is an array of char, not int. "%d" is the
format specifier for int. You mean something like

{
int tmp;
scanf("%d", &tmp);
macht = tmp; /* with optional error-checking */
}
/*Printing the input */
for(i=0;i<14;i++)
{printf("%d",macht);
}
printf("\n");

fscanf(fp,"%d %d %d",&pbas,&e,&inleeslg);


Here is another bug. 'pbas' is a long int. 'e' and 'inleeslg' are
chars. None of them are ints, which is what fscanf("%d") is expecting.
The correct format specifier for 'long int' is "%ld"; the two chars
can be read in using the temporary-variable solution I gave you above.
/*Printing the input again */
for(i=0;i<14;i++)
{printf("%d",macht);


Note that this is *not* a bug, since while 'macht' is a char,
it is passed as an int to 'printf'. However, learning when it is
safe to rely on the integer promotions is a tricky business.
} printf("\n");
}
fclose(fp);

And last but not least,

return 0;
 
V

Villy Kruse

The standard says nothing about being able to associate two FILE stream
pointers with one file. Hence its UB.

It is resource leak, nevertheless; parhaps harmless in this case. The
FILE* returnd by the first call to fopen is lost so that FILE* could never
be closed before the end of the program.



Villy
 
A

Arthur J. O'Dwyer

[...]
It is resource leak, nevertheless; parhaps harmless in this case. The
FILE* returnd by the first call to fopen is lost so that FILE* could never
be closed before the end of the program.

The implementation is required to close all open file handles before
program termination (at least, program termination via 'exit' or
equivalent ('return' from 'main', falling off 'main')). Not a great
idea to rely on this behavior IMO, since it's usually not much harder
and much clearer to explicitly close your files, but not a true
"resource leak" in the way that, say, forgetting to free a malloc'ed
block is.

-Arthur
 
V

Villy Kruse

(e-mail address removed) (An) wrote:

fp=fopen("Factortest","r");
if ((fp=fopen("Factortest","r"))==NULL) printf("Kan datafile niet
openen \n");
[...]
It is resource leak, nevertheless; parhaps harmless in this case. The
FILE* returnd by the first call to fopen is lost so that FILE* could never
be closed before the end of the program.

The implementation is required to close all open file handles before
program termination (at least, program termination via 'exit' or
equivalent ('return' from 'main', falling off 'main')). Not a great
idea to rely on this behavior IMO, since it's usually not much harder
and much clearer to explicitly close your files, but not a true
"resource leak" in the way that, say, forgetting to free a malloc'ed
block is.

A leak is a leak anytime a pointer or a handle to some resource is lost.

Let's say the program is running for months at a time, and the program
fragment is called once an hour on average, the program would in this way
accumulate a lot of opened files which could never be closed until the
program is terminated. Opened file handles are a limited resource in most
environments, and allowing them to leak can lead to long term problems.

A multitasking OS has to care care of lost malloc()ed memory anyway,
just in case the program terminates abnormally. Were that not the case
we would have to restart the OS whenever some program aborts in order
to reclaim its resources.


Villy
 

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,780
Messages
2,569,611
Members
45,277
Latest member
VytoKetoReview

Latest Threads

Top