Program without conditional Statements - Possible ?

  • Thread starter Raghavendra R A V, CSS India
  • Start date
C

Chris Torek

I nearly replied in a similar fashion last night, but then I realized
that it *may* actually be valid (e.g. if used in a function scope) :-(

As someone pointed out recently, you cannot guess wrong all the time.

It *is* valid when in a function, as you note.

On the other hand, it is *not* a constant, as can be seen
by referring to it in a "case" statement, for instance:

void f(int i, int j) {
const int k = min(i, j);

switch (i) {
case k:
puts("i was the min (or equal to j -- degenerate case)");
break;
default:
puts("j was the min");
break;
}
}

Moreover, readonly variables in C cannot be used to dimension
non-VLAs (VLAs being new in C99):

% cat foo.c
const int N = 20;
int a[N];

is illegal in both C89 and C99, and replacing the second line with:

void f(void) {
int b[N];
}

is valid only in C99 (at which point "sizeof b" requires a runtime
evaluation of sizeof, in the abstract machine, though a good compiler
can still optimize it away).

(C++ is, in my opinion, far better than C here. C should have
spelled the keyword "readonly", since it never makes constants.
But then, C has a tradition of misspelling keywords, such as
"typedef" for "do not define a type". :) )
 
S

Sidney Cadot

nrk said:
Real computer scientists don't write in anything less portable than a 2B
pencil. Its a shame that Turing machines are so poor at I/O.

Poor at I/O? Granted, an fseek() is a bit sluggish, but at least there's
no need to check fprintf() results for fear of filling up the tape!

Best regards,

Sidney
 
N

nrk

Arthur said:
((x) && ({foo();}) || ({bar();});

uglier

{[(x])}&(&{{foo}{};)] || ([)[bar][]()]};;)

uglier still

[That was a joke, son. :) Plays off of the fact that the text
you posted was not C, it was just a collection of parens and braces
superficially similar to nrk's C example. So duh, it's uglier.
It's easy to make things ugly when you don't care about sense.]

LOL!! Time to dust up RJH's excellent quote and paraphrase it to suit the
occasion:

If we remove the requirement that the code must work correctly, I can write
a version that will take no memory, run in zero time, and is virtually
indistinguishable from line noise :)

-nrk.
 
S

Sidney Cadot

gabriel said:
In my CS coursework, I ended up coding everything in C/C++ with Visual C++
6, debugging it there too, and also doing Boundschecker tests under
Windows. When when the source was fully clean and debugged, I would
compile under UNIX for submittal. Doing the whole thing under UNIX was
hell and I gave up soon.

<OT>

Just a bit of well-meant advice: don't give up too soon. Persist, if
only to broaden your horizon. Most of the more interesting work in CS is
done on non-Windows platforms. If you don't get acquainted with
alternatives (which aren't so 'alternative' as they may seem from your
perspective), you are severely limiting your options...

Best regards,

Sidney
 
C

CBFalconer

nrk said:
Ashish wrote:
.... snip ...
I ended up initializing an array using...
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
...

*sigh*

Stupid prof, but fortunately the course lasted only 4 months.
I'm still recovering.

Well, you could've used recursion... Now you'll tell me that
functions, if and arithmetic, logical operators were banned as
well :) If that were the case, you should tell your prof:

Real computer scientists don't write in anything less portable
than a 2B pencil. Its a shame that Turing machines are so poor
at I/O.

#include <stdio.h>

int initarray(int *array, int len, int cur) {
if ( cur >= len ) return 0;
array[cur] = cur+1;
return initarray(array, len, ++cur);
}

int main(void) {
int a[10];
size_t i;

initarray(a, sizeof a/sizeof a[0], 0);
for ( i = 0; i < sizeof a/sizeof a[0]; ++i )
printf("%d\n", a);
return 0;
}


No no no. Replace the for statement with:

showarray(a, sizeof a/sizeof a[0], 0);

and my suggestion for showarray is:

void showarray(int *array, size_t len, size_t cur)
{
if (cur < len ) {
array[cur] = cur+1;
showarray(array, len, ++cur);
}
}

which I recently discovered will not create stack overflows with
gcc -O2. initarray could be similar.
 
K

Keith Thompson

Chapter and verse, please.

C90 5.1.2.2.3 "Program Termination":

A return from the initial call to the main function is equivalent
to calling the exit function with the value returned by the main
function as its argument. If the main function executes a return
that specifies no value, the termination status returned to the
host environment is undefined.

C90 6.6.6.4, "The return statement":

If a return statement without an expression is executed. and the
value of the function call is used by the caller, the behavior is
undefined. Reaching the } that terminates a function is
equivalent to executing a return statement without an expression.

It's not illegal, and it doesn't invoke undefined behavior (since
there's no "caller"), but I'd say that returning an undefined
termination status to the host environment doesn't qualify as "OK".
 
E

E. Robert Tisdale

CBFalconer said:
void showarray(int *array, size_t len, size_t cur) {
if (cur < len) {
array[cur] = cur + 1;
showarray(array, len, ++cur);
}
}

which I recently discovered
will not create stack overflows with gcc -O2.

If you inspect the assembler emitted by gcc,
you will discover that the compiler automatically
"flattens" the recursion into a loop for you
so that showarray never actually calls itself.

The GNU C/C++ compilers will not flatten every recursion yet
but they are getting better and this optimization is now common
in other compilers as well now.
 
R

Richard Heathfield

Ashish said:
gabriel said:
Just out of curiosity... How did you come up with this question? School
assignment, or just something you thought up, perhaps?

Possible. When I was in school, my prof (who was barred from teaching any
programming courses) divided the class into 4 groups. One group was
supposed to write a C program, for a particular problem, using for loops,
the other with gotos and the other using both, and the last one, using
neither.

I ended up initializing an array using...
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
...

*sigh*

That sigh is the sigh of a man who hasn't yet considered the possibility of
using C code to write C code!

You will observe that I have nothing up either sleeve (except my arms, of
course).

Watch closely...

#include <stdio.h>

#define LIMIT 1000 /* adjust to taste */

int main(void)
{
unsigned long i = 0;
puts("#include <stdio.h>\n\nint main(void)\n{");
printf(" int a[%d];\n", LIMIT);
for(i = 0; i < LIMIT; i++)
{
printf(" a[%lu] = %lu;\n", i, i + 1);
}
/* whatever else you want the program to do can go here,
* or you can just generate the array this way and then
* hand-hack the generated code. Of course, you don't
* show the professor /this/ program!
*/

puts(" return 0;\n}");

return 0;
}

And hey! Presto! The silly professor is confounded by Gaussian optimisation!
 
D

donLouis

C90 5.1.2.2.3 "Program Termination":

A return from the initial call to the main function is equivalent
to calling the exit function with the value returned by the main
function as its argument. If the main function executes a return
that specifies no value, the termination status returned to the
host environment is undefined.

C90 6.6.6.4, "The return statement":

If a return statement without an expression is executed. and the
value of the function call is used by the caller, the behavior is
undefined. Reaching the } that terminates a function is
equivalent to executing a return statement without an expression.

It's not illegal, and it doesn't invoke undefined behavior (since
there's no "caller"), but I'd say that returning an undefined
termination status to the host environment doesn't qualify as "OK".

I bring this up for three reasons;

1) I'm sitting at home coding in exercises from a text book. Stuff
like
#include <stdio.h>
int main(void) {
printf("whatever\n");
/* more basic i/o stuff */
}
no filtering, no checking the return status (if I even can), just
learning basic for, while, do, case, whatever. There are plenty
of these types of programs that don't _necessarily_ need a return.

2) Infinite loops. In the bulk of the code that I write these
days, returning from main (or most other functions) is a fatal
error.

3) <OT?> Adding "dummy" returns to GUI code, just to silence
a warning that, based on the cited text above, I think is
harmless.

Comments or corrections are welcome.
 
D

donLouis

Doesn't it depend on *where* you put the semicolon? ;-)

I was semi-serious, actually. Which is the correct interpretation?

1. the white space is irrelevant, therefore, it's a one liner.
2. the semi-colon implies a statement, therefore, it's a two liner.
 
N

Nils Petter Vaskinn

I was semi-serious, actually. Which is the correct interpretation?

1. the white space is irrelevant, therefore, it's a one liner.

So by definition any program can be turned into a one liner. Just do the
preprosessing first. Is there a limit to line length?
2. the semi-colon implies a statement, therefore, it's a two liner.

Arn't you allowed statements in one liners?

int main(){for(;;){}}

No additional semicolon :)
 
M

Martin Dickopp

Nils Petter Vaskinn said:
So by definition any program can be turned into a one liner. Just do
the preprosessing first. Is there a limit to line length?

Yes. A conforming C99 implementation is not required to support logical
source lines (i.e. source lines after backslash-newline-sequences have
been removed) longer than 4095 characters (5.2.4.1#1).

Martin
 
N

Nils Petter Vaskinn

Yes. A conforming C99 implementation is not required to support logical
source lines (i.e. source lines after backslash-newline-sequences have
been removed) longer than 4095 characters (5.2.4.1#1).

So the rule would be: "A one liner can be no more that 4095 characters".
Since a conforming compiler could reject it if it was longer.

Does anyone know if different compilers enforce this limit? I've never
written a 4096 character line so I wouldn't know.
 
D

Dan Pop

In said:
C90 5.1.2.2.3 "Program Termination":

A return from the initial call to the main function is equivalent
to calling the exit function with the value returned by the main
function as its argument. If the main function executes a return
that specifies no value, the termination status returned to the
host environment is undefined.

C90 6.6.6.4, "The return statement":

If a return statement without an expression is executed. and the
value of the function call is used by the caller, the behavior is
undefined. Reaching the } that terminates a function is
equivalent to executing a return statement without an expression.

It's not illegal, and it doesn't invoke undefined behavior (since
there's no "caller"), but I'd say that returning an undefined
termination status to the host environment doesn't qualify as "OK".

The question is what the standard says, not what you or anyone else does.
The C89 standard *explicitly* allows this programming construct, therefore
it is OK from the standard's point of view.

Not every program is supposed to return a meaningful value to the host
environment. If I end all my toy programs with a return statement it is
to get a clean compile from gcc -Wall, not because the program termination
status has any meaning to anyone (which is always the case with programs
that only return one exit status: it contains as much information as no
exit status at all).

Dan
 
K

Keith Thompson

donLouis said:
1) I'm sitting at home coding in exercises from a text book. Stuff
like
#include <stdio.h>
int main(void) {
printf("whatever\n");
/* more basic i/o stuff */
}
no filtering, no checking the return status (if I even can), just
learning basic for, while, do, case, whatever. There are plenty
of these types of programs that don't _necessarily_ need a return.

2) Infinite loops. In the bulk of the code that I write these
days, returning from main (or most other functions) is a fatal
error.

3) <OT?> Adding "dummy" returns to GUI code, just to silence
a warning that, based on the cited text above, I think is
harmless.

My advice: Develop good habits now. If a function is declared to
return an int, return an int; main is no different this respect than
any other function.

Ok, that's not quite true, for two reasons. First, C99, unlike C90,
explicitly requires falling off the end of main to be equivalent to
"return 0;" (a feature that I dislike, but there it is). Second, for
most functions, if you don't want to return a value, you can declare
it to return void; you don't really have that option for main.

But the point remains: even if you're not going to use the returned
value, it's easier just to be consistent about returning a value than
to worry about when you can get away with not doing so.
 
K

Keith Thompson

The question is what the standard says, not what you or anyone else does.
The C89 standard *explicitly* allows this programming construct, therefore
it is OK from the standard's point of view.

Please cite the section of the standard that defines its use of the
term "OK".

In the absence of such a definition, I will feel free to use the term
in its colloquial sense, based on my own opinion. Failing to return a
value from main() is not "OK". What I mean by that is that it's a bad
idea. It doesn't violate the standard, it doesn't invoke undefined
behavior (unless you call main() recursively and try to use the
result), and it doesn't make hair grow on the palms of your hands.

It was perfectly clear that that was what I meant.

OK?
Not every program is supposed to return a meaningful value to the host
environment. If I end all my toy programs with a return statement it is
to get a clean compile from gcc -Wall, not because the program termination
status has any meaning to anyone (which is always the case with programs
that only return one exit status: it contains as much information as no
exit status at all).

My environment is configured to complain if I run a program that
returns a failure status. <OT>I use tcsh with the $printexitvalue
variable set.</OT> If you don't care about the status returned by a
toy program, that's fine, but I do care about it.
 
C

CBFalconer

Peter said:
CBFalconer said:
nrk wrote:
.... snip ...
int main(void) {
int a[10];
size_t i;

initarray(a, sizeof a/sizeof a[0], 0);
for ( i = 0; i < sizeof a/sizeof a[0]; ++i )
printf("%d\n", a);
return 0;
}


No no no. Replace the for statement with:

showarray(a, sizeof a/sizeof a[0], 0);

and my suggestion for showarray is:

void showarray(int *array, size_t len, size_t cur)
{
if (cur < len ) {
array[cur] = cur+1;
showarray(array, len, ++cur);
}
}


Which is equivalent to the for loop above exactly how? (Hint: no output)


I do seem to have goofed thoroughly. :-[ Maybe the "arr[cur] =
cur+1;" line should be revised :)
 
D

donLouis

My advice: Develop good habits now. If a function is declared to
return an int, return an int; main is no different this respect than
any other function.

Ok, that's not quite true, for two reasons. First, C99, unlike C90,
explicitly requires falling off the end of main to be equivalent to
"return 0;" (a feature that I dislike, but there it is). Second, for
most functions, if you don't want to return a value, you can declare
it to return void; you don't really have that option for main.

But the point remains: even if you're not going to use the returned
value, it's easier just to be consistent about returning a value than
to worry about when you can get away with not doing so.

In the above example #1 and #3, I do habitually return a value from
main. My contention is that it is _not_ required in C89/90. For a
long time, I thought that it was. Your point on consistency,
however, is well taken.
 
P

pete

donLouis said:
In the above example #1 and #3, I do habitually return a value from
main. My contention is that it is _not_ required in C89/90. For a
long time, I thought that it was. Your point on consistency,
however, is well taken.

It is easier for me to memorize, that

int main(void)
{
return 0;
}

will work in all C programs, in all standards,
than it is to know the variations of what will work
according to year of the standard and whatever else might matter.
 
S

Sidney Cadot

pete said:
It is easier for me to memorize, that

int main(void)
{
return 0;
}

will work in all C programs, in all standards,

Shouldn't you use EXIT_SUCCESS in C89?

Best regards,

Sidney
 

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

Latest Threads

Top