I am learning C: a little problem with a simple source code

S

Seebs

Oh great, somebody who knows how computers work, I've been looking
for somebody like that to explain something...
:)

Oh yes, people could die...soooooooo, please explain how a
common OS, such as say, Windows(TM), uses the return value
from main()? Or for that matter, a TRUE Unix(TM)? Or any
other OSs that you are an expert on?

All of the ones I'm aware of use it as an indicator of the success or
failure status of a process. While the Windows GUI mostly ignores
those (mostly), in the DOS or Unix shells, either way, if you use a
command as a conditional, the return status of main() is what determines
whether it's "true" or "false".
And while you're on the subject, how should a computer
expert such as yourself set the return value of main() to be
correct?

EXIT_SUCCESS or EXIT_FAILURE.
Can you define what conditions would cause me to set it one
way or another? Of course, I'm assuming that since the
ANSI C committee decreed that main() have a specific set
of return values, every computer in the world conforms
to those values and does something useful with them, so
I would have perfect "portability" between platforms
for my "correct" C code, and nobody would die as a result
of my using an incorrect return value...

Not everything does something useful with them, but most of the major
systems you'll encounter do, in fact, do something useful with them.

And while I'm sure you think you're being hilariously witty and sarcastic
about people dying... Attitudes like yours are why computers DO kill
people sometimes, because someone assumes that something that worked once
in a test will be fine, and then in the real world, the random hunk
of memory that ended up determining whether to take path A or path B through
some other code ends up having a bit set, and Whoops.

If you want to see the roots of how this works, grab yourself a Unix
prompt (cygwin will do), and try:

int main(void) {
return 3;
}

compile this, run it, and then "echo $?", and you should get "3". Probably.
(In a Unix-like environment, it's actually guaranteed. It's not necessarily
portable more broadly.)

The values which have formal definitions are:
0, EXIT_SUCCESS: Indicate success
EXIT_FAILURE: Indicate failure

Interestingly, this is true even on platforms (such as VMS) where a program
exit status of 0 is failure; the runtime is required to correctly translate
those three values to the environment's standards.
Also, what's "winmain()"? I've seen that a lot, returns
something called a "Windows handle", what's up with that?

That would be traditional Windows being what is called a "freestanding
environment", which is to say, one which doesn't conform to the C standard's
rules for a "hosted" environment. Normally, a "freestanding environment"
is used for something like a tiny embedded board with little to no operating
system. One of the interesting side effects was that some Windows compilers
chose not to offer a working <stdio.h> or the related functionality when
they were used in the mode where they started execution at winmain().
(I believe I've seen claims that at least one omitted *sprintf* too in
this mode. Which is allowed, and goes to show why you always want a
hosted implementation if possible.)
You know, I've asked these questions here before, but
never received an answer, but I'm sure that's because
there wasn't a computer expert such as yourself to answer
them...

I'd guess it's most likely because they're only sort of topical. Either
that or because your hostile and sarcastic tone made people assume you
weren't serious. (Me, I don't care; you may not be planning to read the
response, but someone else might.)

-s
 
P

Pasquale Frega

Hi all, very thanks for your suggestions, you are a treasure for me;
however i have a new version of my code:


#include <stdio.h>;
#include <math.h>;
const long double Pi = 3.14159265358979323846;
float area(float r) { /*define area
function*/
return(r*r*Pi);
}
float perimeter(float r) { /*define perimeter
function*/
return(2*Pi*r);
}
int main(void) {
system("cls");
float r=0; char c; int i;
/*define radius and c variable used to control the behaviour
of program; 'i' needs to clean input buffer*/
printf("This programm calculate Area and Perimenter of a Circle");
do {
printf("\n\nPlease insert radius value (in cm): ");
fflush(stdout);
scanf("%f", &r); /*input of the radius value*/
if(r>0) {
printf("\nArea is cm2: %.2f \n\nPerimeter is cm: %.2f\n", area(r),
perimeter(r)); /*call area perimeter and
function*/
} else printf("\nValue must to be a valid number\n");
while(i=getchar()!='\n');
/*clean input buffer*/
r=0;
/*reset radius value*/
printf("\nPress any key to continue ESC to exit");
c=getch();
} while(c!='\e');
}

Now it works fine; i follow a simple rule: write as fewer as possible.
Is it right (comments apart)?..........About main, on my compiler
there is not different about the various versions, official and
no............... i like "void main()", but such as a lot of you say
and such as i understand, i will use "int main(void)".............for
the rest, i think, the importat is that the program must to do exactly
as i want, the rest is irrelevant.
 
J

John Bode

[snip]
But the fact remains that the language is defined the way it is,
and conforming to that definition shouldn't be at all difficult.
Failing to do so can *sometimes* indicate a lack of attention to
detail that can and should reduce the reader's trust in the rest
of the code (Schildt's books are a classic example).

IMHO, the blame lies not with the authors of the Standard, but with
the authors of books and tutorials (most of whom had access to the
Standard and therefore should have known better) who decided, for
no apparent reason, to tell their readers that "void main(void)"
is perfectly valid.

A thousand times this. One of the primary reasons for software
quality issues in C code is authors like Schildt teaching bad practice
and faulty information. And that bad information is now being passed
on second-hand by authors who learned from Schildt.

Of course, any C programmer who responds to this with a "so what, who
cares" is a a far bigger part of the problem.
 
B

Bill Reid

All of the ones I'm aware of use it as an indicator of the success or
failure status of a process. While the Windows GUI mostly ignores
those (mostly), in the DOS or Unix shells, either way, if you use a
command as a conditional, the return status of main() is what determines
whether it's "true" or "false".
Hmmmm, "if you use a command as a conditional", you mean
like a shell script? OK, maybe we're getting a little
closer...maybe...
EXIT_SUCCESS or EXIT_FAILURE.
Damn, and you were almost on the right track...your
post returned "EXIT_BEGGING_THE_QUESTION"...
Not everything does something useful with them, but most of the major
systems you'll encounter do, in fact, do something useful with them.
OK, maybe I'll answer the question myself, since you're
having some problems doing so...on the "TRUE" Unix(TM) I
worked with for years, there was this circular log that
kept track of all the apps that were launched on the system,
and one of the columns in the table showed the exit status
of the app...simple enough? Sys admins could peruse this
log and maybe glean some type of insight into how the
system was working and being used...

The problem is, the fact that an application developer
chose to return a particular value doesn't really say
a hell of lot about the system function, so I doubt sys
admins really paid much attention to that column.

Now if there were a RULE that EXIT_FAILURE would only
be set for what could be considered system problems during
the running of an app, such as failure to allocate memory,
the log would be a lot more useful...but the "C" standard
is mute on the topic as are the people who claim that
incorrect return values COULD KILL PEOPLE DAMMIT!!!!
And while I'm sure you think you're being hilariously witty and sarcastic
about people dying...

No, not that hilarious, just pointing out you were
indulging in some unwarranted fear-mongering...and
you felt free to continue in that vein, even after
being laughed at about it:
Attitudes like yours are why computers DO kill
people sometimes, because someone assumes that something that worked once
in a test will be fine,

Yes, ASSUMPTIONS are the key to what I'm asking
about, DAMMIT!!!
and then in the real world, the random hunk
of memory that ended up determining whether to take path A or path B through
some other code ends up having a bit set, and Whoops.
Since you can't specify why the particular
conditional in question would be set, you're
really part of the illogical problem and not
the solution and have PROBABLY KILLED MILLIONS
AS A RESULT!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you want to see the roots of how this works, grab yourself a Unix
prompt (cygwin will do), and try:

int main(void) {
return 3;
}

compile this, run it, and then "echo $?", and you should get "3". Probably.
(In a Unix-like environment, it's actually guaranteed. It's not necessarily
portable more broadly.)

The values which have formal definitions are:
0, EXIT_SUCCESS: Indicate success
EXIT_FAILURE: Indicate failure

Interestingly, this is true even on platforms (such as VMS) where a program
exit status of 0 is failure; the runtime is required to correctly translate
those three values to the environment's standards.
Objection, motion to strike, argumentative, unresponsive,
irrelevant...
That would be traditional Windows being what is called a "freestanding
environment", which is to say, one which doesn't conform to the C standard's
rules for a "hosted" environment.

Maybe your post should return "EXIT_TAUTOLOGY"; everything
just refers back to the "C" standard, and yet what I asked
about is how the "C" standard can control the behavior of
various operating systems when it can't even specify what
the behavior of an application developer should be in returning
a SPECFIC value to the operating system...
Normally, a "freestanding environment"
is used for something like a tiny embedded board with little to no operating
system. One of the interesting side effects was that some Windows compilers
chose not to offer a working <stdio.h> or the related functionality when
they were used in the mode where they started execution at winmain().
(I believe I've seen claims that at least one omitted *sprintf* too in
this mode. Which is allowed, and goes to show why you always want a
hosted implementation if possible.)
Your honor, motion to bind and gag the witness!!!
I'd guess it's most likely because they're only sort of topical.

It's about one of the most frequently answered questions
here (right up there with not casting the return value of
malloc())!!! How can it NOT be topical, IT'S ALWAYS BROUGHT
UP WHETHER ASKED FOR OR NOT!!??!!!
Either
that or because your hostile and sarcastic tone made people assume you
weren't serious.

I'm 100% serious because when I program an effin'
computer I expect "hospital corners" for every effin'
thing I do...if I do something, I want to know EXACTLY
how it will impact the system and my application and
my users (which I TRULY care about, because largely
"my users" is just me, if I did this more "professionally"
I would probably take the more slip-shod attitude toward software
quality displayed frequently here).

(Me, I don't care; you may not be planning to read the
response, but someone else might.)
I'm reading, so here's a scenario: one application I wrote
automatically downloads hundreds of files a day from all over
the Internet, different web-sites, different formats, etc.

Sometimes, they don't put the file up at the time I
expect it to be there, so the program can't download it.
Other times, due to some sanity checking of various
strings in the files to attempt to determine if they
are the correct files I wanted to download in the first
place (since at times, the webmasters may change what
files they put at a certain link), the file might
not be written to disk until manual perusal to
verify its contents.

Both of those could be considered "failures" of
the application to do what I wanted it to do; so
should I set "EXIT_FAILURE"? (And just to cut to
the chase, I don't, I handle stuff like that, and
Internet connectivity problems, etc., in my own application
"logs", and would only use "EXIT_FAILURE" for something
like a failure to allocate, even though I have no
idea what PRACTICAL benefit that provides me,
since that is separately logged as well.)
 
B

Bill Reid

You return 0 to indicate that the program exited normally, and
EXIT_FAILURE to indicate that it encountered some sort of error
condition.
Objection, motion to strike, non-responsive...
Many OSes allow scripts or other programs to use these values, to
indicate whether a program did what was intended or not.
OK, that's a little better, although an OS "allow"ing
a script that does something undefined and unknowable
is not the same thing as the OS doing something with
the value...and you snipped out my other pertinent question
and either deliberately or otherwise misunderstood it, you
know, the thing about WHY you would set either "EXIT_SUCCESS"
or "EXIT_FAILURE" from main(); maybe the other "computer
expert" can answer that one better...
 
K

Kulin Remailer

Oh yes, people could die...soooooooo, please explain how a
On the OS I work on (not a PC OS) every program is supposed to set a return
code. It doesn't matter if it's a main program or a subprogram (nor should
it, since today's main program may be tomorrow's subprogram and today's
subprogram may be tomorrow's main program). Also, and this is a big
difference from UNIX/Linux the return codes are /fully documented/. I know
that last part is a big shocker, but yeah, code worth writing to sell to
people is code that needs to give good messages and documented meaningful
return codes. Actually, our convention on that OS is to give two types of
codes, a reason code and a return code and those are standardized with
groups of normal, warning, error, severe error, etc. return code and then a
reason code that specifies, within that category, the reason for the error.

We don't give error messages like opps, sorry, etc. Do yourself and
everybody else a favor. Set return codes and document them. It's the Right
Thing To Do.
 
S

Seebs

Hmmmm, "if you use a command as a conditional", you mean
like a shell script? OK, maybe we're getting a little
closer...maybe...
Yes.

OK, maybe I'll answer the question myself, since you're
having some problems doing so...

Er, what?
on the "TRUE" Unix(TM) I
worked with for years, there was this circular log that
kept track of all the apps that were launched on the system,
and one of the columns in the table showed the exit status
of the app...simple enough? Sys admins could peruse this
log and maybe glean some type of insight into how the
system was working and being used...
Yup.

The problem is, the fact that an application developer
chose to return a particular value doesn't really say
a hell of lot about the system function, so I doubt sys
admins really paid much attention to that column.

They may have paid attention sometimes.
Now if there were a RULE that EXIT_FAILURE would only
be set for what could be considered system problems during
the running of an app, such as failure to allocate memory,
the log would be a lot more useful...

That would not be a suitable rule for a language standard. It might
be a suitable rule for an operating system standard.

It would be a spectacularly stupid rule, though, because there are
widespread systems which have very well established rules for such
behavior.
but the "C" standard
is mute on the topic

As it should be. If you want to do something more specific, you need to
do it in a way specific to your environment.
as are the people who claim that
incorrect return values COULD KILL PEOPLE DAMMIT!!!!

That's because we're talking about what actually happens in computers,
not what would have been an interesting alternative design to consider
in a parallel universe where neither Windows nor Unix existed.
No, not that hilarious, just pointing out you were
indulging in some unwarranted fear-mongering...

Except that it's not unwarranted.
and
you felt free to continue in that vein, even after
being laughed at about it:

That's because the "being laughed at" was stupid and ignorant.
Yes, ASSUMPTIONS are the key to what I'm asking
about, DAMMIT!!!

Maybe you should focus less on being a jerk and more on articulating
your questions, then?
Objection, motion to strike, argumentative, unresponsive,
irrelevant...

So you weren't actually asking the question you asked.
Maybe your post should return "EXIT_TAUTOLOGY"; everything
just refers back to the "C" standard, and yet what I asked
about is how the "C" standard can control the behavior of
various operating systems when it can't even specify what
the behavior of an application developer should be in returning
a SPECFIC value to the operating system...

Okay, you seem to be under some kind of strange delusions about the
relationship of a language standard to the rest of the world.

Operating systems exist, and have requirements that vary based on
what they are operating systems for. Language specs don't get to
control that. Language specs offer limited standardized functionality,
and if you need functionality beyond what they can offer, you have to
go look at other specs.

If you want the *portable* C answer, the only values that mean anything
are 0, EXIT_SUCCESS, and EXIT_FAILURE, and there is no guarantee that
every operating system everywhere does anything with them. However,
realistically, any implementation that's hosted will at the very least do
something vaguely reasonable with these.

If you want an answer that's more specific to a platform, then your
answer necessarily depends on the specifics of that platform and
environment.
It's about one of the most frequently answered questions
here (right up there with not casting the return value of
malloc())!!!

The winmain() question isn't.
How can it NOT be topical, IT'S ALWAYS BROUGHT
UP WHETHER ASKED FOR OR NOT!!??!!!

It can not be topical because it turns out to be a question about specific
operating systems, to which different systems have different answers, not
a question about the language.
I'm 100% serious because when I program an effin'
computer I expect "hospital corners" for every effin'
thing I do...if I do something, I want to know EXACTLY
how it will impact the system and my application and
my users

Then you'd be well served by learning that a computer system is more than
one thing. The language is not the same thing as the operating system,
which is not the same thing as the hardware. If you want to know what
specific return values do, look at the operating system, because that's what
is doing something with them.
I'm reading, so here's a scenario: one application I wrote
automatically downloads hundreds of files a day from all over
the Internet, different web-sites, different formats, etc.

That's nice.
Both of those could be considered "failures" of
the application to do what I wanted it to do; so
should I set "EXIT_FAILURE"?

That is up to you and your feelings about what your specific operating
system does with the values.
(And just to cut to
the chase, I don't, I handle stuff like that, and
Internet connectivity problems, etc., in my own application
"logs", and would only use "EXIT_FAILURE" for something
like a failure to allocate, even though I have no
idea what PRACTICAL benefit that provides me,
since that is separately logged as well.)

The main practical benefit is that it offers other programs a way to
find out whether your program worked without needing to know that much
about your program.

Let's say I want to grab a bunch of files. Right now, I'm using wget:
for u in $urls; do
wget "$u"
done

But I want to know which URLs to retry again later:

retry_later=""
for u in $urls; do
wget "$u" || retry_later="$retry_later $u"
done

I can do this, because I know that wget will "succeed" if it gets the
file, and "fail" if it doesn't-get the file. I don't have to know what
specific values it returns, and I don't really care in this case. And
if I want to switch to using Luke Mewburn's ftp instead of wget, I just do:

lukemftp "$u" || retry_later="$retry_later $u"

and so on and so forth.

And then I try the billreid downloader, and whaddya know. He returns
"success" whether or not he succeeds, so with his program, I have to do:
/path/to/billreid.logfile
billreidget "$u"
if grep -q "FAILED" /path/to/billreid.logfile; then
retry_later="$retry_later $u"
fi

.... which works, because I know that grep will indicate success or failure
appropriately.

The thing is, in the real world, people will sometimes do stuff like
# see whether we can grab specification file
if wget "$specfile_url"; then
program_robot "$specfile"
fi

because they know that they'll know whether the application succeeded or
failed.

And if someone then comes in and says "I'll return success unless there was
a system error of some sort, even if I do not actually succeed in achieving
the task I was assigned, because I can just look in the log files", someone
ends up programming the robot with stale data, or a corrupted file, or...

And yes, we mostly know better, and people are usually pretty careful with
this kind of thing. Usually. But there are people killed every year
because software fails, and software fails in part because people don't
do error checking, and they don't do error checking because people think
it's hilarious overdramatization to imagine that anyone could actually be
hurt if you don't check errors or provide the error indicators that people
would be checking for...

But a big part of the problem is that you're expecting a language standard
to dictate terms to operating systems, when it actually goes the other way;
operating systems dictate what can be implemented on them, language standards
look for things they can expect everyone to provide some way of handling.
Virtually all operating systems can distinguish in some way between
"success" and "failure" of a program. If you need more than that, you are
outside what a language standard can possibly specify, because not all
operating systems have more than that.

So, again: If you want more information than this, go read the specs for
the operating system or systems you care about, but it's not going to be
a feature of this language or any other, because languages don't get to
decide what operating systems do or don't support.

-s
 
K

Keith Thompson

Pasquale Frega said:
Hi all, very thanks for your suggestions, you are a treasure for me;
however i have a new version of my code:


#include <stdio.h>;
#include <math.h>;
const long double Pi = 3.14159265358979323846;
float area(float r) { /*define area
function*/
return(r*r*Pi);
}
float perimeter(float r) { /*define perimeter
function*/
return(2*Pi*r);
}
int main(void) {
system("cls");
float r=0; char c; int i;
/*define radius and c variable used to control the behaviour
of program; 'i' needs to clean input buffer*/
printf("This programm calculate Area and Perimenter of a Circle");
do {
printf("\n\nPlease insert radius value (in cm): ");
fflush(stdout);
scanf("%f", &r); /*input of the radius value*/
if(r>0) {
printf("\nArea is cm2: %.2f \n\nPerimeter is cm: %.2f\n", area(r),
perimeter(r)); /*call area perimeter and
function*/
} else printf("\nValue must to be a valid number\n");
while(i=getchar()!='\n');
/*clean input buffer*/
r=0;
/*reset radius value*/
printf("\nPress any key to continue ESC to exit");
c=getch();
} while(c!='\e');
}

Your code layout makes my eyes bleed, especially with long lines being
folded (probably by some news software somewhere).

Here's a reformatted version of your program, with some bugs correct.
It's still not perfect (I find that I have to type control-D twice to
exit). Study the changes I've made and the comments I've added. Note
in particular that I've dropped the call to getch(), which is
non-standard.

#include <stdio.h>
#include <math.h>

const long double Pi = 3.14159265358979323846;

float area(float r) {
return r*r*Pi;
}

float perimeter(float r) {
return 2*Pi*r;
}

int main(void) {
/* system("cls"); */
/*
* Why do you want to clear my screen when I run your program?
* And what if I run it on a system that doesn't have a "cls"
* command -- or, worse, that has a "cls" command that does
* something else? If I want to erase my screen, possibly
* destroying information that has nothing to do with your
* program, I can do it myself, thankyouverymuch.
*/

float r=0;
int c;
int items_read;
/* define radius and c variable used to control the behaviour
of program; 'i' needs to clean input buffer*/

printf("This programm calculate Area and Perimenter of a Circle");
do {
printf("\n\nPlease insert radius value (in cm): ");
fflush(stdout);
items_read = scanf("%f", &r); /*input of the radius value*/
if (items_read == 1 && r > 0.0) {
printf("\nArea is cm2: %.2f \n\nPerimeter is cm: %.2f\n",
area(r),
perimeter(r));
}
else {
printf("\nValue must to be a valid number\n");
}

while ((c=getchar()) != '\n' && c != EOF)
;
} while (c != EOF);
return 0;
}
 
B

Bill Reid

On the OS I work on (not a PC OS) every program is supposed to set a return
code. It doesn't matter if it's a main program or a subprogram (nor should
it, since today's main program may be tomorrow's subprogram and today's
subprogram may be tomorrow's main program). Also, and this is a big
difference from UNIX/Linux the return codes are /fully documented/. I know
that last part is a big shocker, but yeah, code worth writing to sell to
people is code that needs to give good messages and documented meaningful
return codes. Actually, our convention on that OS is to give two types of
codes, a reason code and a return code and those are standardized with
groups of normal, warning, error, severe error, etc. return code and thena
reason code that specifies, within that category, the reason for the error.

We don't give error messages like opps, sorry, etc. Do yourself and
everybody else a favor. Set return codes and document them. It's the Right
Thing To Do.

Yeah, that's just ter-rrrrrific, but again, you're missing the
point, which was about the return value of main(), which is a
mere binary value indicating "success" or "failure" without
any explanation of what constitutes "success" or "failure"...

Now as to other errors that may be logged on various systems as
an application is running, as you describe, a system may have a
very robust (or not!) system of error logging, but this has nothing
to do with the ANSI C standard-specified values from main().
Rather these are usually system-specific and hard to port from
system to system without substantial compatibility library
work or some-such, and thus represent perhaps the greatest
challenge to portability of "C" and other languages below
the GUI level...
 
B

Bill Reid

Er, what?


They may have paid attention sometimes.


That would not be a suitable rule for a language standard.  It might
be a suitable rule for an operating system standard.
OK, sure, that's why various operating systems have error
logging standards baked in...so what was the friggin' point
of putting in a largely useless return value in the "C" standard?
It would be a spectacularly stupid rule, though, because there are
widespread systems which have very well established rules for such
behavior.
I'm not sure I'm following...it's stupid because it's a feature
of widespread systems? Is this a back-handed MS slam?

But I GUESS what you're TRYING to say is that the return
value of main() has no particular use because the OS either
does or does not supply useful error logging, but the ANSI
C committee put it in the standard for writing scripts based
on relatively small C programs used as commands and basically
no other purpose...maybe they should have stated THAT as their
"rationale" (did they?), which would supply some actual guidance as
to under what circumstances you should set a particular value...
As it should be.  If you want to do something more specific, you need to
do it in a way specific to your environment.
Or do it myself...
That's because we're talking about what actually happens in computers,
not what would have been an interesting alternative design to consider
in a parallel universe where neither Windows nor Unix existed.
No, we're not, you had your chance to prove a certain
return value could kill people, particularly without a
clear "intervening event" like some goofball writing some
dumb script that launches nuclear missiles because he
thinks that somebody is following a rule that he already
knows a lot of people don't follow...
Except that it's not unwarranted.
Yes it is...extraordinary claims require extraordinary
proof, you provided nothing other than hand-waving...
That's because the "being laughed at" was stupid and ignorant.
What have I written that would lead you to conclude I was
either stupid or ignorant, other than it is fun to insult
people who share different, possibly more correct, opinions
than you?
Maybe you should focus less on being a jerk and more on articulating
your questions, then?
What have I written that would lead you to posit I have
not asked clear articulate questions? You snipping them
out and answering questions of your own liking does not
count...
So you weren't actually asking the question you asked.
Sorry, been watching the late afternoon Conrad Murray trial
on TV, you just seem to be out of order on this topic...
Okay, you seem to be under some kind of strange delusions about the
relationship of a language standard to the rest of the world.
Well, that makes two of us, since I think we're in total agreement
that a language standard cannot control the OS...so what was the
point of passing a binary value to the OS again? Basically
scripts?
Operating systems exist, and have requirements that vary based on
what they are operating systems for.

Or the whims and/or stupidity of the OS designers...
Language specs don't get to
control that.  Language specs offer limited standardized functionality,
and if you need functionality beyond what they can offer, you have to
go look at other specs.
Sure...but hey, think about this: instead of a binary value for
main(), allow the full use of the int to allow OS-specified return
values that would actually mean something...sound reasonable? Just
an idea...probably IS stupid...
If you want the *portable* C answer, the only values that mean anything
are 0, EXIT_SUCCESS, and EXIT_FAILURE, and there is no guarantee that
every operating system everywhere does anything with them.

Whew...your logic does not resemble our Earth logic...I'm not
even going to try on this one, it'd be like debating the crazy
homeless
guy shouting to himself on the street corner...
However,
realistically, any implementation that's hosted will at the very least do
something vaguely reasonable with these.
I was previously not amused with your use of the term "hosted" in
relation to Windows(TM), and it's not getting any funnier...
If you want an answer that's more specific to a platform, then your
answer necessarily depends on the specifics of that platform and
environment.


The winmain() question isn't.


It can not be topical because it turns out to be a question about specific
operating systems, to which different systems have different answers, not
a question about the language.
I guess it's always a question about pointless pedantry versus
real life...on a scale of 0 to 100 of possible PROGRAMMER errors,
"misuse" of the return value of main() is about a 0.0000000025,
and cannot reasonably foreseeably kill anybody.

You've only been told this about 8 billion times, you might
just concede that simple point and move along to something
slightly more important, like the precise average amount of
lint your navel collects in a day...
Then you'd be well served by learning that a computer system is more than
one thing.  The language is not the same thing as the operating system,
which is not the same thing as the hardware.  If you want to know what
specific return values do, look at the operating system, because that's what
is doing something with them.
EXACTLY. You've once again managed to expertly beg the
question, just like the crazy homeless guy begs for money...
That's nice.
What's really nice is another snip-a-roo so you
could do the following pointless "fancy footwork":
That is up to you and your feelings about what your specific operating
system does with the values.
No it isn't; what you snipped out was just the tip
of the iceberg of my program requirements...the OS
very kindly logs various types of Internet failures,
but I have to parse them to get to what I need to
do, and I have to do a whole lot more and of course
this has NOTHING to do with the return value of main()...
The main practical benefit is that it offers other programs a way to
find out whether your program worked without needing to know that much
about your program.
I as a person, both as the user of the program and person
who wrote to the program to do certain things, have no need
or desire to know whether my program "worked" or not, but
I have a burning need to know exactly WHY it didn't WORK
(you know, what you disingenuously snipped out).
Let's say I want to grab a bunch of files.  Right now, I'm using wget:
        for u in $urls; do
                wget "$u"
        done
What do they call this, "script kiddie" work? Yeah, I've
used that command, and I guess I could have used it in a
script to do what I wanted to do...as long as the script
was about 10 times as long as this friggin' long
post...
But I want to know which URLs to retry again later:

        retry_later=""
        for u in $urls; do
                wget "$u" || retry_later="$retry_later $u"
        done
See, it's getting longer already...now make it do the downloads
according to dozens of different schedules, making sure that it
actually has the right files, you know, the stuff you snipped
out, along with automatically placing the files in hundreds
of different directories according to the types of data, then
invoking a hundred or so file parsing routines to pull the
wanted data out and loaded automatically into my database,
you know, stuff like that...when do you think you'll have my
script ready?
I can do this, because I know that wget will "succeed" if it gets the
file, and "fail" if it doesn't-get the file.  I don't have to know what
specific values it returns, and I don't really care in this case.

See, I actually kind of care, but you may have a point, if
you don't get your file, try, try again, and don't worry if
the file is corrupt, just go ahead and download it anyway,
it's easier to fix a corrupted database days or weeks later
if you're not aware of it at download...
And
if I want to switch to using Luke Mewburn's ftp instead of wget, I just do:

                lukemftp "$u" || retry_later="$retry_later $u"

and so on and so forth.

And then I try the billreid downloader, and whaddya know.  He returns
"success" whether or not he succeeds, so with his program, I have to do:

        >/path/to/billreid.logfile
        billreidget "$u"
        if grep -q "FAILED" /path/to/billreid.logfile; then
                retry_later="$retry_later $u"
        fi

... which works, because I know that grep will indicate success or failure
appropriately.
Yeah, I guess we work on two entirely different levels of
software...
The thing is, in the real world, people will sometimes do stuff like
        # see whether we can grab specification file
        if wget "$specfile_url"; then
                program_robot "$specfile"
        fi

because they know that they'll know whether the application succeeded or
failed.

And if someone then comes in and says "I'll return success unless there was
a system error of some sort, even if I do not actually succeed in achieving
the task I was assigned, because I can just look in the log files", someone
ends up programming the robot with stale data, or a corrupted file, or...
Yeah, that was exactly why I don't use the "script kiddie"
approach, I'm watching a scheduled download now, it's giving me
all the information on success or failure, a few days ago one
of the "5pm weekdays except certain holidays" files was retitled
and I got an error message, which automatically pulled up
the file so I could get the new title string, I selected
the download configuration menu item and replaced the
string to look for with the new one and now I don't get
the message anymore...sure am sorry I don't rely on the
return value of main()...
And yes, we mostly know better, and people are usually pretty careful with
this kind of thing.  Usually.  But there are people killed every year
because software fails, and software fails in part because people don't
do error checking, and they don't do error checking because people think
it's hilarious overdramatization to imagine that anyone could actually be
hurt if you don't check errors or provide the error indicators that people
would be checking for...
Give it up...I've told you at least a dozen effin' times
my goal is to get much more PRECISE error messages to avoid
any type of unwanted error, and I just don't get that from
main()...aren't you worried that you're confusing the
"children", or is that your goal?
But a big part of the problem is that you're expecting a language standard
to dictate terms to operating systems, when it actually goes the other way;
operating systems dictate what can be implemented on them, language standards
look for things they can expect everyone to provide some way of handling.

Nope. If it's undefined, it's a waste of time, and the
return value of main() is for all practical intents and
purposes undefined, except for "script kiddies"...
Virtually all operating systems can distinguish in some way between
"success" and "failure" of a program.

Sure, "running" or "not responding" seem to be popular...
If you need more than that, you are
outside what a language standard can possibly specify, because not all
operating systems have more than that.
Well, sure, and in many cases I have to provide it
myself, maybe just for the sake of the holy "portability"
(remember, my own error logging written in "C" is fully
portable as long as it doesn't rely on OS-specific logging)...
So, again:  If you want more information than this, go read the specs for
the operating system or systems you care about, but it's not going to be
a feature of this language or any other, because languages don't get to
decide what operating systems do or don't support.
EXACTLY. Thanks for agreeing with me, AND for calling
me an "idiot" and "ignorant" in the process...
 
B

Barry Schwarz

snip
On EBCDIC systems y is 169. Consider also that they might type in a
capital 'Y' and get surprised if it gets interpreted as quitting time.

On EBCDIC systems, 169 == 0xa9 == 'z'
You've got some non-portable stuff in your code but then again, I used a
goto so both of us are evil and doomed forever more.

I came up with this variant when I saw your original post.

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

static const double pi_approximation =
3.1415926535897932384626433832795028841971693993751;
static char string[32767];

/* Area of a circle with radius r */
double area (double r)
{
return (r * r * pi_approximation);
}

/* Perimeter of a circle with radius r */
double perimeter (double r)
{
return (2.0 * pi_approximation * r);
}

/* Safely collect a string (due to Jack Klein) */
char * getsafe (char *buffer, int count)
{
char *result = buffer, *np;
if ((buffer == NULL) || (count < 1))
result = NULL;
else if (count == 1)
*result = '\0';
else if ((result = fgets (buffer, count, stdin)) != NULL)
if (np = strchr (buffer, '\n'))
*np = '\0';
return result;
}


int main (void)
{
double r = 0;
int c = 0;
int converted;
printf ("This programm calculate Area and Perimenter of a Circle");
do
{
doofus:
printf ("\n\nPlease give radius value (in cm):");
fflush (stdout);
getsafe (string, sizeof string);
r = atof (string);
if (r <= 0)
{
if (r == 0 && string[0] == '0')
{
puts ("Both perimeter and radius are zero, but you knew
that.");
}
else
{
puts ("No such thing as a negative radius in Euclidean
geometry.");
goto doofus;

Why not use the continue statement and eliminate both the goto and the
label?
}
}
printf ("Area = %.2f cm^2\n", area (r));
printf ("Perimeter = %.2f cm\n", perimeter (r));

It is a tad unusual to leave a space between the function name and the
argument list.
 
S

Seebs

But the return value of main() is not binary, ANSI just standardized
ways of generically specifying success and failure. The meaning of
any other value is implementation defined (not undefined).

Right. And the thing is... Some systems let you return anything you want.
Some do things like filtering it down to an 8-bit value, or whatever else.

But this is *beyond what the language can control*.
There are many parts of the standard which are implementation defined,
particularly when it comes to interfacing to the system - the syntax
of filenames, for example. The exact meaning of exit(3) is as
implementation specific as the meaning of fopen("lpt1:", "w").

Exactly. This is in the same category of stuff as the file interface.
The C standard carefully doesn't specify the form of file names... But any
*given* implementation will, and will usually do it usefully.

-s
 
N

Nick Keighley

n Nov 3, 7:05 am, Malcolm McLean <[email protected]>

some people actually work on systems were incorrect operation of the
software *could* kill someone.

Even Blackberry servers going out for a day or two can cause massive
inconvenience. Hopefully you don't work on anything like that...
Objection, motion to strike, non-responsive...

I'm sorry?

Q: "explain how an OS uses the return value from main()"
A: "a value of 0 indicates success and EXIT_FAILURE indicates failure"

That's about all the standard can say. On Unix the value returned can
be used by the parent process, for instance a shell script to detect
success or failure. VMS used to output an error message in a standard
format for that OS.

so you stuck your snarky answer in the middle of his respose for...
jollies?
OK, that's a little better, although an OS "allow"ing
a script that does something undefined and unknowable
is not the same thing as the OS doing something with
the value...

your point being?
and you snipped out my other pertinent question
and either deliberately or otherwise misunderstood it, you
know, the thing about WHY you would set either "EXIT_SUCCESS"
or "EXIT_FAILURE" from main();

you set the value to EXIT_SUCCESS for success and to EXIT_FAILURE for
failure. presumably you know enough about the application domian
domain you are programming for to judge if something has succeeded or
not.
maybe the other "computer
expert" can answer that one better...

expert: one who used to be a spurt
spurt: a drip under pressure
 
N

Nick Keighley

Hi all, very thanks for your suggestions, you are a treasure for me;
however i have a new version of my code:

<snip>

your code is still rather poorly laid out.
Now it works fine;
good!

i follow a simple rule: write as fewer as possible.

"write as little as possible" or "write as few lines as possible"?

Sounds like a variant on
"everything should be made as simple as possible, but no simpler"
Some Scientist

I'd say strive for clarity. So don't pack your code really tightly if
it obscures your purpose. Write simple straightforward code. Only
deviate from this if you need (*really* need) the performance or some
other constraint pushes you away from perfect clarity.
Is it right (comments apart)?..........About main, on my compiler
there is not different about the various versions, official and
no............... i like "void main()",

I wish I was decended from bears but my wishes don't change the facts.
but such as a lot of you say
and such as i understand, i will use "int main(void)".............for
the rest, i think, the importat is that the program must to do exactly
as i want, the rest is irrelevant.

layout, clarity etc. if your progarm is going to have any sort of
extended lifetime. Unlikely in this case but it's sensible to start
with good habbits.
 
N

Nick Keighley

On 2011-11-03, Bill Reid <[email protected]> wrote:

OK, sure, that's why various operating systems have error
logging standards baked in...so what was the [quasi-expletive] point
of putting in a largely useless return value in the "C" standard?

why is a success/failure indication useless? Millions of Unix scipts
use it every day. If the file failed to copy then we give up or try to
get the important value from somewhere else.

If you don't care if your program fails do you care if anything fails?
Does your progarm have any error handling? read RISKS for some
interesting results of poor error handling.

Ah. Backup. I suspect some (rather noddy) backup systems on unix are
based on tar then cp. If one of these fails but the failure was
ignored you might *think* your files were backed up. I'll leave you to
worry what data loss might do.

<snip rant>
 
N

Nick Keighley

On Wed, 2 Nov 2011 21:03:34 -0700, Dann Corbit <[email protected]>
I came up with this variant when I saw your original post.
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
static const double pi_approximation =
3.1415926535897932384626433832795028841971693993751;
static char string[32767];
/* Area of a circle with radius r */
double area (double r)
{
   return (r * r * pi_approximation);
}
/* Perimeter of a circle with radius r */
double perimeter (double r)
{
   return (2.0 * pi_approximation * r);
}
/* Safely collect a string (due to Jack Klein) */
char * getsafe (char *buffer, int count)
{
   char *result = buffer, *np;
   if ((buffer == NULL) || (count < 1))
       result = NULL;
   else if (count == 1)
       *result = '\0';
   else if ((result = fgets (buffer, count, stdin)) != NULL)
       if (np = strchr (buffer, '\n'))
           *np = '\0';
   return result;
}
int main (void)
{
   double r = 0;
   int c = 0;
   int converted;
   printf ("This programm calculate Area and Perimenter of a Circle");
   do
   {
doofus:
       printf ("\n\nPlease give radius value (in cm):");
       fflush (stdout);
       getsafe (string, sizeof string);
       r = atof (string);
       if (r <= 0)
       {
           if (r == 0 && string[0] == '0')
           {
               puts ("Both perimeter and radius are zero, but you knew
that.");
           }
           else
           {
               puts ("No such thing as a negative radius in Euclidean
geometry.");
               goto doofus;

Why not use the continue statement and eliminate both the goto and the
label?

continue is nearly as nasty as goto. They can both be eliminated in
this case
It is a tad unusual to leave a space between the function name and the
argument list.

I do it all the time. Why shouldn't it follow the normal text
convention?

goto-less version

int main (void)
{
double r = 0;
int c = '\N';
int converted;

printf ("This program calculate the Area and Perimenter of a
Circle");

do
{
printf ("\n\nPlease give radius value (in cm):");
fflush (stdout);
getsafe (string, sizeof string);
r = atof (string);

if (r <= 0)
{
if (r == 0 && string[0] == '0')
{
puts ("Both perimeter and radius are zero, but you
knew that.");
}
else
{
puts ("No such thing as a negative radius in Euclidean
geometry.");
}
}
else
{
printf ("Area = %.2f cm^2\n", area (r));
printf ("Perimeter = %.2f cm\n", perimeter (r));
puts ("Do you want to continue? (y or elsewhere to
exit):");
fflush (stdout);
c = getchar ();
}
}
while (toupper (c) == 'Y');

return 0;
}
 
B

Ben Bacarisse

Nick Keighley said:
I do it all the time. Why shouldn't it follow the normal text
convention?

The main argument (no pun intended) is that the programming usage
follows from mathematics: f(x) and so on. Even having seen the inserted
space for some time (I thinks it's relatively new) I still can't shake
off the sense it gives of a parenthetical remark:

f(x) + y // f applied to x plus y
f (x) + y // f plus y (and by the way, x)

Silly, I know, but it's only fair that there be a comment from someone
who hates this style!

<snip>
 
B

Bill Reid

some people actually work on systems were incorrect operation of the
software *could* kill someone.
Yes, so what does that have to do with the return value of main()?
That was the question, can you think of a single case where somebody
died as a result of an incorrect return value of main()? Can you
even come up with a far-fetched hypothetical (primarily for amusement
value, of course)?

I mean, more people have died of the flu because somebody spit
on the sidewalk, and by "more" I mean maybe a 0.3% chance
of one person in the history of the world...
Even Blackberry servers going out for a day or two can cause massive
inconvenience.  Hopefully you don't work on anything like that...
No, my software works, other "professional programmers" write
the crap that fails me on a regular basis...some of which probably
post here about people dying as the result of the return value of
main() (that type of illogic COULD be deadly when applied to
"life-critical" applications).
I'm sorry?

Q: "explain how an OS uses the return value from main()"
A: "a value of 0 indicates success and EXIT_FAILURE indicates failure"
Q: Could you explain how a doctor uses a Magic 8-Ball?
A: A value of "outlook uncertain" indicates "outlook uncertain"...
That's about all the standard can say.

Sooooo...you don't have a reasonable point either...great...
On Unix the value returned can
be used by the parent process, for instance a shell script to detect
success or failure.

Great, that's an actual answer, now we've established something,
it was like pulling teeth to get to this simple point, but there
it is: if you write very simple C programs that perform a single
function, if the program fails to complete that function for
any reason, you know what to do, in the anticipation that the
program will be used in a shell script.

Soooooo...is that it? Anything else to add? Anything to say
about a much more complex program where this binary return value
and use in a script wouldn't be of much use or sense?
OK.

so you stuck your snarky answer in the middle of his respose for...
jollies?
He begged the question for...well, being dense, defensive,
or what?
your point being?
I asked specifically about the OS, but I can accept
the simple script explanation...still am having trouble
understanding how anybody is going to die as a PROXIMATE
FORESEEABLE result of an incorrect return value of main()...
you set the value to EXIT_SUCCESS for success and to EXIT_FAILURE for
failure.

YOUR HONOR, THE WITNESS IS REFUSING TO ANSWER HOW DOCTORS
USE MAGIC 8-BALLS!!!
presumably you know enough about the application domian
domain you are programming for to judge if something has succeeded or
not.
Yup, as it turns out, I DID know that, I was just wondering
if you did...but that's "outlook uncertain"...
 
M

Malcolm McLean

 One of the interesting side effects was that some Windows compilers
chose not to offer a working <stdio.h> or the related functionality when
they were used in the mode where they started execution at winmain().
(I believe I've seen claims that at least one omitted *sprintf* too in
this mode.  Which is allowed, and goes to show why you always want a
hosted implementation if possible.)
Yes, that's a terrible nuisance. If stderr is vandalised then a lot of
code which should be portable becomes non-portable.

As a non-debugger user, I also like to print diagnostics. I ended up
writing a special console for the task.
 
M

Malcolm McLean

you
know, the thing about WHY you would set either "EXIT_SUCCESS"
or "EXIT_FAILURE" from main(); maybe the other "computer
expert" can answer that one better...

/*
Here's a program which enhances a medical X-ray image, essential so
a human expert can analyse the image to see if a disease is present.
*/

int main(int argc, char **argv)
{
unsigned char *image;
int width, height;
int err;

if(argc != 3)
{
/* we were called with the incorrect number of arguments. Tell
user how to use program */
printf("Usage: enhanceimage <xrayimage.jpeg> <enahncedoutput.jpeg>
\n");
return EXIT_FAILURE;
}
image = loadjpeg(argv[1], &width, &height);
if(!image)
return EXIT_FAILURE;
err = enhanceimage(image, width, height);
if(err != 0)
return EXIT_FAILURE; /* for some reason algorithm to enhance image
fell over */
err = savejpeg(argv[2], image, width, height);
if(err != 0)
return EXIT_FAILURE;

free(image);
/* image loaded, enhanced and saved correctly */
return 0;
}

Now some medical programming person is using a high-level language,
maybe Perl, to dish up the enhanced images to a webserver.

He writes

$enhancedimagename = "temp.jpeg"; # put the enhanced image in a
temporary buffer
$err = system($rawimagename, $enhancedimagename);
if($err == 0)
diplayimage(enhancedimagename);
else
# do something here to indicate that the image held in temp.jpeg is
NOT an enhanced image for the correct patient.


This might not be the best-designed system in the world. But it is
correct. The return provides an easy way to tell the calling script
whether the image was correctly enhanced or not.
 

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
474,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top