Memory allocation for an initialized character pointer;

A

arunajob

Hi all,

If I have a piece of code something like this

void main(void)
{
char * p1="abcdefghijklmn";
.............................................

}

For p1 and whatever it points to , where is the memory allocated. Is
it on heap or stack or
some other common global area. I am assuming it should be either on
stack or some global area. Unless
a user does a malloc storage space cannot be allocated on heap is my
assumption. Can someone
throw some light on how compilers do this.

What if the above piece of code is changed to something like

void main(void)
{
char *p1;
char a[20]="abcdefgh";

strcpy(p1,a);
}

Now where is the space allocated for p1 and whatever it points to
after strcpy.

Thanks in advance.

Regards,
Ar
 
A

Antoninus Twink

If I have a piece of code something like this

void main(void)

Oh dear, you've done it now...
<waits for the shit to hit the fan as a thousand Heathfield fanboiz get
ready to show off the depth of their C knowledge>
{
char * p1="abcdefghijklmn";
}

For p1 and whatever it points to , where is the memory allocated. Is
it on heap or stack or some other common global area.

Typically it will be stored in the read-only .data segment.
What if the above piece of code is changed to something like

char *p1;
char a[20]="abcdefgh";

strcpy(p1,a);

Now where is the space allocated for p1 and whatever it points to
after strcpy.

p1 is uninitialized, so will be pointing at a random memory location.
It's likely that you won't be able to write to that memory, and your
program will segfault.
 
K

Keith Thompson

If I have a piece of code something like this

void main(void)
{
char * p1="abcdefghijklmn";
.............................................

}

The correct declaration for main is "int main(void)". See the
questions 11.12a said:
For p1 and whatever it points to , where is the memory allocated. Is
it on heap or stack or
some other common global area. I am assuming it should be either on
stack or some global area. Unless
a user does a malloc storage space cannot be allocated on heap is my
assumption. Can someone
throw some light on how compilers do this.

Storage for p1 itself (the pointer object) has what the standard calls
"automatic storage duration". That means it's created on entry to the
main function, and deallocated on exit from the main function. On a
typical system, it will be allocated on the "stack", but
implementations are allowed to use whatever mechanism meets the
standard's requirements.

Storage for the string literal, "abcdefghijklmn" plus the terminating
'\0' character, has "static storage duration". This storage exists
for the entire lifetime of the program. Again, implementations are
allowed to use whatever mechanism meets the standard's requirements.
What if the above piece of code is changed to something like

void main(void)
{
char *p1;
char a[20]="abcdefgh";

strcpy(p1,a);
}

p1 and a (a pointer object and an array object) have "automatic
storage duration"; in a typical implementation, they'll be stored on
the "stack" (but see above). Notionally, the contents of the string
literal are stored somewhere with static storage duration, but since
it's used only to initialize a, the compiler doesn't actually need to
keep it around.

But the strcpy() call will most likely fail. It attempts to copy 8
bytes ("abcdefg" plus the trailing '\0') to whatever memory p1 points
to, but you haven't allocated any memory for p1 to point to. It might
appear to work correctly, it might terminate your program with an
error message (if you're lucky), or it might clobber some critical
piece of memory and cause arbitrarily bad things to happen, limited
only by whatever safeguards are imposed by your operating system.
This is what the standard calls "undefined behavior".

You could allocate memory using malloc():

p1 = malloc(strlen(a) + 1);
if (p1 == NULL) {
/* malloc failed, handle the error somehow */
}
else {
strcpy(p1, a); /* p1 now points to a copy of the string */
}

[...]

Many questions like this can be answered by checking the comp.lang.c
FAQ (URL above).
 
J

jameskuyper

Hi all,

If I have a piece of code something like this

void main(void)

'void' is not a legal return type for main(), though many compilers do
their users a disservice by allowing it. Change it to int, and add a
corresponding 'return' statement down below.
{
char * p1="abcdefghijklmn";
.............................................

}

For p1 and whatever it points to , where is the memory allocated. Is
it on heap or stack or
some other common global area. I am assuming it should be either on
stack or some global area. Unless
a user does a malloc storage space cannot be allocated on heap is my
assumption. Can someone
throw some light on how compilers do this.

The memory is statically allocated. The result is roughly equivalent
to writing

int main(void)
{
static const char some_name[] = {'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', '\0'};
char *p1 = (char*)some_name;

The actual location for such static memory is up to your compiler. As
usual, Twink has given you an answer that might be relevant to your
particular compiler, or it might be complete nonsense. The only way to
know for sure is to check your compilers' documentation, which would
have been a better answer than the one Twink gave you.
What if the above piece of code is changed to something like

void main(void)
{
char *p1;
char a[20]="abcdefgh";

strcpy(p1,a);
}

Now where is the space allocated for p1 and whatever it points to
after strcpy.

String literals are treated differently when they initialize char*
pointers than they are when they initialize char arrays. In the first
case, static memory is allocated for the contents of the string
literal, and the pointer is initialized with a value that points to
the first character of the array. It is not safe to attempt to write
to that array.

In the second case, the contents of the string literal are used to
directly initialize the declared array; no separate storage is
allocated. Whether or not the memory has static storage duration or
automatic storage duration depends upon the declaration of the array;
the same is true about whether or not the array is declared as
'const'.

In this case, both p1 and a are both allocated as memory with
automatic storage duration, which usually, but not necessarily, means
that it is allocated from a hardware stack. You'll need to check your
compiler's documentation to find out exactly how this is handled.

Each time a statement block is entered, objects defined in that block
with automatic storage duration need to be re-initialized. This isn't
an issue for your program, because it contains only one block which is
never reentered; the only such objects in your program could be
handled the same way as static memory, without causing any problems.
However, in the more general case this means that the information
needed to re-initialize the object each time the block is entered must
be stored somewhere else. The standard says nothing about how this
information is stored, and there are many different ways to do it. For
small objects, the data might even be stored as part of the
initialization instructions, rather than in a seperate block of
memory.

Now we come to the nasty part. p1 is uninitialized before the call to
strcpy(). As a result, the behavior of your program is undefined. In
principle, even attempting to read the value of p1 might make your
program abort, and there have been real machines where that would have
happened. In practice, what is likely to happen is that p1 contains a
bit pattern about which you know nothing, including whether or not it
represents a valid memory location. That pattern will be interpreted
as if it did represent a pointer, and that pointer value will be
passed to strcpy(). strcpy() will attempt to copy the string located
in 'a' to this unknown memory location. The consequences of doing so
could be catastrophic; on systems with poor memory protection, like MS/
DOS, it was actually possible to damage devices with a write to the
wrong memory location; it was certainly easy to mess up the
configuration of your computer, requiring at least a reboot. On more
modern OSs (a category that includes many OSs that predate MS/DOS by
decades), such code is like to produce a memory segment violation,
which will halt your program. If it doesn't halt, that means that p1
happens to point at a memory location that your program actually has
permission to write to, such as &p1. However, this will be an
unpredictable part of the memory allocated to your program, which
stands a good chance of making some other unpredictable part of your
program fail.

In short: NEVER use the value of an uninitialized variable; be
particularly careful about uninitialized pointer variables. You should
make sure that p1 points at something before you ask strcpy() to copy
something to the location p1 points at. You should also make sure that
whatever p1 points at, it is big enough to store the thing that you're
copying to it.
 
S

s0suk3

The correct declaration for main is "int main(void)".

But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:

<quote>
5.1.2.2.1 Program startup

1 The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though any
names may be used, as they are local to the function in which they are
declared):

int main(int argc, char *argv[]) { /* ... */ }

or equivalent;9) or in some other implementation-defined manner.

<end quote>

Thus, the prototype shown by the OP is also correct.

Sebastian
 
K

Keith Thompson

The correct declaration for main is "int main(void)".

But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:

<quote>
5.1.2.2.1 Program startup [snip]
or equivalent;9) or in some other implementation-defined manner.

<end quote>

Thus, the prototype shown by the OP is also correct.

That depends on what you mean by "correct". And no, I'm not playing
word games; it really does depend on what you mean by "correct".

An implementation is allowed, but not required, to support "void
main(void)". (In fact, this is covered by the general permission to
support extensions; the "or in some other implementation-defined
manner" wording in 5.1.2.2.1 is redundant.)

So if the OP's particular implementation, for whatever reason,
supports "void main(void)" -- which means that it must *document* it,
not just accidentally fail to reject it -- then "void main(void)" is
arguably correct *for that implementation*. But it's not portable; it
can be rejected, or can cause undefined behavior, on any
implementation that doesn't choose to support it. For example, the
status code returned to the environment when the program terminates is
normally the int value returned from main(), or passed to exit(). If
main() doesn't return an int value, what status code does the
environment see? The standard certainly doesn't say; the
implementation may or may not document it.

And there is absolutely no advantage to using "void main(void)" rather
than "int main(void)". You give up portability for the sake of
.... what exactly do you gain? Well, you can omit the "return 0;" or
"exit(EXIT_SUCCESS);" at the end of main() -- but C99 lets you omit
that anyway.

So yes, "void main(void)" can be "correct" in some narrow
circumstances. Or it can be incorrect.

But "int main(void)" is unquestionably correct. (Assuming, of course,
that you're using a C89 or better compiler that recognizes the "void"
keyword in this context -- but "void main(void)" is certainly no
better in that case.)

The above assumes a hosted implementation. In a freestanding
implementation (very loosely, an embedded system), "int main(void)"
might not be valid. But it's safe to assume that the OP is using a
hosted implementation.

(Cue the trolls whining that the correct declaration of main is the
only thing we discuss here.)
 
V

vippstar

The correct declaration for main is "int main(void)".

But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:

<quote>
5.1.2.2.1 Program startup

1 The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though any
names may be used, as they are local to the function in which they are
declared):

int main(int argc, char *argv[]) { /* ... */ }

or equivalent;9) or in some other implementation-defined manner.

<end quote>

Thus, the prototype shown by the OP is also correct.

It seems correct to you means "compile on some implementations"
Clearly you need to participate in implementation-specific groups to
share your implementation specific expertise, because here, it's not
correct.
 
S

s0suk3

But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:
<quote>
5.1.2.2.1 Program startup [snip]
or equivalent;9) or in some other implementation-defined manner.
<end quote>
Thus, the prototype shown by the OP is also correct.

That depends on what you mean by "correct".  And no, I'm not playing
word games; it really does depend on what you mean by "correct".

I meant correct in the sense that it's valid according to the
standard.
An implementation is allowed, but not required, to support "void
main(void)".  (In fact, this is covered by the general permission to
support extensions; the "or in some other implementation-defined
manner" wording in 5.1.2.2.1 is redundant.)

But this would be the kind of extension that a compiler wouldn't be
able to accept in strictly conforming mode, isn't it? By being
explicitly mentioned in the standard, a compiler can now accept it in
so-called conforming mode.
So if the OP's particular implementation, for whatever reason,
supports "void main(void)" -- which means that it must *document* it,
not just accidentally fail to reject it -- then "void main(void)" is
arguably correct *for that implementation*.  But it's not portable; it
can be rejected, or can cause undefined behavior, on any
implementation that doesn't choose to support it.

Of course, "in an implementation-defined manner" means it will be
different across implementations. Personally I prefer to define it to
return int, and to omit the return statement. But I think it isn't
very accurate to say that "void main(void)" is "incorrect", only
because it will be rejected by some implementations.
For example, the
status code returned to the environment when the program terminates is
normally the int value returned from main(), or passed to exit(). If
main() doesn't return an int value, what status code does the
environment see? The standard certainly doesn't say; the
implementation may or may not document it.

Common sense says: 0 (or, more generally, the value that indicates
"normal" program termination, in case there's some obscure OS where 0
isn't such a value).

Sebastian
 
K

Keith Thompson

(e-mail address removed) writes:
If I have a piece of code something like this
void main(void)
{
   char * p1="abcdefghijklmn";
    .............................................

The correct declaration for main is "int main(void)".
But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:
<quote>
5.1.2.2.1 Program startup [snip]
or equivalent;9) or in some other implementation-defined manner.
<end quote>
Thus, the prototype shown by the OP is also correct.

That depends on what you mean by "correct".  And no, I'm not playing
word games; it really does depend on what you mean by "correct".

I meant correct in the sense that it's valid according to the
standard.

Substituting "valid" for "correct" doesn't make it any clearer.

It's correct, valid, or whatever you want to call it only with respect
to a specific implementation, and only if that implementation
explicitly supports it.
But this would be the kind of extension that a compiler wouldn't be
able to accept in strictly conforming mode, isn't it? By being
explicitly mentioned in the standard, a compiler can now accept it in
so-called conforming mode.

No. The requirement in 5.1.2.2.1 is not a constraint, which means
that violating it invokes undefined behavior; no diagnostic is
required. Since no strictly conforming program can use
"void main(void)", and no diagnostic is required for it, anything an
implementation does with it is within the bounds of the standard.

BTW, "strictly conforming" applies to programs, not to implementations
or modes. An implementation is conforming or it isn't.
Of course, "in an implementation-defined manner" means it will be
different across implementations. Personally I prefer to define it to
return int, and to omit the return statement. But I think it isn't
very accurate to say that "void main(void)" is "incorrect", only
because it will be rejected by some implementations.

I certainly wouldn't call it "correct".
Common sense says: 0 (or, more generally, the value that indicates
"normal" program termination, in case there's some obscure OS where 0
isn't such a value).

Common sense doesn't necessarily apply. I've used a compiler that
does the equivalent of "exit(1)" if you fall off the end of main()
without executing a return statement. This was perfectly valid
behavior according to the C90 standard (it wasn't a C99 compiler).
 
S

s0suk3

(e-mail address removed) writes:
(e-mail address removed) writes:
If I have a piece of code something like this
void main(void)
{
   char * p1="abcdefghijklmn";
    .............................................
}
The correct declaration for main is "int main(void)".
But it's not the /only/ correct one. There's also "int main(int, char
**)", or anything your implementation supports:
<quote>
5.1.2.2.1 Program startup
[snip]
or equivalent;9) or in some other implementation-defined manner.
<end quote>
Thus, the prototype shown by the OP is also correct.
That depends on what you mean by "correct".  And no, I'm not playing
word games; it really does depend on what you mean by "correct".
I meant correct in the sense that it's valid according to the
standard.

Substituting "valid" for "correct" doesn't make it any clearer.

It's correct, valid, or whatever you want to call it only with respect
to a specific implementation, and only if that implementation
explicitly supports it.

Yes, but, again, I was talking in regard to the standard, not to any
particular implementation.
No.  The requirement in 5.1.2.2.1 is not a constraint, which means
that violating it invokes undefined behavior; no diagnostic is
required.  Since no strictly conforming program can use
"void main(void)", and no diagnostic is required for it, anything an
implementation does with it is within the bounds of the standard.

What!? I'm not following. The quote I made from the standard mentions
three prototype forms for main: "int main(void)", "int main(int, char
**)" and "some other implementation-defined manner". Now, "void
main(void)" would fall under the third category; am I wrong? What do
you mean by saying that a strictly conforming program can't use "void
main(void)"?
BTW, "strictly conforming" applies to programs, not to implementations
or modes.  An implementation is conforming or it isn't.



I certainly wouldn't call it "correct".

If the standard says it is, why not?

Sebastian
 
S

s0suk3

(e-mail address removed) said:



Firstly, the Standard does not require any implementation to provide
support for *any* entry point other than int main(void), int main(int,
char **), and exact equivalents. (The rules for freestanding
implementations are even looser, but let's not go there just now.) There
is certainly no requirement to provide support for void main(void).

Therefore, even if a particular implementation defines a meaning for void
main(void), the behaviour of such a program on some *other* (arbitrary)
implementation is undefined.

So far, the bottom line remains the same: it *is* correct; it simply
isn't guaranteed to work on every compiler.
Secondly, a strictly conforming program is one that "shall use only those
features of the language and library specified in this International
Standard.2) It shall not produce output dependent on any unspecified,
undefined, or implementation-defined behavior, and shall not exceed any
minimum implementation limit."

Since void main(void) is not specified by the Standard, and also since it
can't be demonstrated that the very use of void main(void) does not
produce output dependent on any unspecified, undefined, or
implementation-defined behaviour, it cannot be used in a strictly
conforming program.

Now that's a shocker. Does that mean that, say, bit-fields in
structures can't be used in a strictly conforming program? (Whether
bit-fields are stored from right to left or from left to right is
implementation-defined.) In fact, does that mean that variables of
type int, long, or any type other than char, can't be used in a
strictly conforming program because their sizes are also
implementation-defined?
The Standard doesn't say it's correct. It says that implementations are
allowed to define a meaning for it. But implementations are allowed to
define a meaning for anything they like - they can even give meaning to
Ook! programs if they want. But that doesn't make Ook! programs "correct"
in C terms.

But they'd be providing Ook! support as an extension (which would be
quite an useful extension, btw!). Accepting void main(void) isn't an
extension.

Sebastian
 
R

raashid bhatt

Hi all,

If I have a piece of code something like this

void main(void)
{
char * p1="abcdefghijklmn";
.............................................

}

For p1 and whatever it points to , where is the memory allocated. Is
it on heap or stack or
some other common global area. I am assuming it should be either on
stack or some global area. Unless
a user does a malloc storage space cannot be allocated on heap is my
assumption. Can someone
throw some light on how compilers do this.

What if the above piece of code is changed to something like

void main(void)
{
char *p1;
char a[20]="abcdefgh";

strcpy(p1,a);

}

Now where is the space allocated for p1 and whatever it points to
after strcpy.

Thanks in advance.

Regards,
Ar
in your first example
char *p1 will be allocated on stack not on heap but "abcdefghijklmn"
will be stored as global
now comming to your second example i am sorry to say your code is
wrong ....see

as you declare a pointer without initializing it so where is points
is dependent on your linker and OS it will generally point to 0 ( that
is a null pointer) ....
so you cannot copy bytes to it strcpy(p1, a) ; that is wrong

right way to do it is

char *p1 = NULL;
p1 = a;
then no need for strcpy();

even in this example the pointer will still be allocated on the stack
not on heap;
 
B

Bart van Ingen Schenau

So far, the bottom line remains the same: it *is* correct; it simply
isn't guaranteed to work on every compiler.

No. The phrase "some other implementation-defined manner" means that
void main() is only correct if the implementation documents it as
being so.
If the implementation does not document void main() as a possible
entry point, then using void main() with that implementation results
in UB, which means that this use of void main() can not be correct.

So, you can"t say without qualification that void main() is correct.
You can at most say that it is correct for certain implementations.
Now that's a shocker. Does that mean that, say, bit-fields in
structures can't be used in a strictly conforming program? (Whether
bit-fields are stored from right to left or from left to right is
implementation-defined.) In fact, does that mean that variables of
type int, long, or any type other than char, can't be used in a
strictly conforming program because their sizes are also
implementation-defined?

No, because you can write programs that don't depend on the
implementation defined aspects of bitfields or the integer types.

For example, this is a strictly conforming program:
<cut>
#include <stdio.h>
struct bits {
int value:4;
};
int main(void)
{
struct bits result;
int lhs, rhs;

lhs = 4;
rhs = 3;
result.value = lhs + rhs;
printf("%d\n", result.value);
return 0;
}
<cut>

The program is strictly conforming, because the output does not depend
on the choices that an implementation may have made for the
unspecified or implementation-defined behaviours or values.
Sebastian

Bart v Ingen Schenau
 
N

Nick Keighley

On Oct 1, 12:04 am, (e-mail address removed) wrote:

since The Standard doesn't mention heaps there is no restriction on an
implementaion using the heap (or stack) for whatever it pleases. The
static variables area could be stack or heap. (on old Macs the heap
was on the stack).


they have to allocate a block of memory before program startup.
How they do this is the implementors business. It is common
to just grab a lump of memory for statis data.

What if the above piece of code is changed to something like
void main(void)
{
    char *p1;
    char a[20]="abcdefgh";
    strcpy(p1,a);

Now where is the space allocated for p1 and whatever it points to
after strcpy.

in your first example
char *p1 will be allocated on stack not on heap but "abcdefghijklmn"
will be stored as global
now comming to your second example i am sorry to say your code is
wrong ....see

as you declare a pointer without initializing  it so where is points
is dependent on your linker and OS it will generally point to 0 ( that
is a null pointer) ....

if by "generally" you mean "usually" I don't think this is so.
In my experience it contains whatever "random" crap has been
left on the stack. Many OSs *don't* clear the memory
before dishing it out to processes.
so you cannot copy bytes to it strcpy(p1, a) ; that is wrong

right way to do  it is

char *p1 = NULL;

initialising it to NULL is not necessary
p1 = a;
then no need for strcpy();

yes, but that may not be what the user wanted. he might
want to modify what p points to.
 
J

James Kuyper

Now that's a shocker. Does that mean that, say, bit-fields in
structures can't be used in a strictly conforming program? (Whether
bit-fields are stored from right to left or from left to right is
implementation-defined.)

No, a program can use bit fields. You need to make sure that it is not
written in such a way that it's observable behavior depends upon the
order of the bit fields within the structure.
... In fact, does that mean that variables of
type int, long, or any type other than char, can't be used in a
strictly conforming program because their sizes are also
implementation-defined?

No, a program can use all standard integer types, so long as it makes
sure that the observable behavior of the program does not depend upon
the sizes of those types. This is possible, because the standard sets
minimum values for the *_MAX macros for each standard type, and maximum
values for each of the *_MIN macros for signed integer types. There are
many different ways to achieve this goal; the simplest is to ensure that
an no calculation using 'int', for instance, involves a number that
might fall outside of the range -32767 (sic!) to 32767.

Because of the things that the standard deliberately does NOT say about
the precision of floating point mathematics, it's very difficult to use
floating point types in any meaningful way in a strictly conforming
program. The addition of two floating point numbers, for instance,
cannot in general be exact; but the standard imposes no requirements on
how inexact the result can be; in principle, a floating point
implementation could therefore give a result of 3.0 for 1.0+1.0. No real
implementation would do things that badly, but unless __STDC_IEC_559__
is #defined by the implementation, calculations involving 'float', for
instance, might have errors much larger than you might otherwise expect.
 
S

s0suk3

(e-mail address removed) said:





It seems that we have a terminology disagreement again. I don't see it as
being "correct". I know it fails on at least two implementations that I
use regularly.

But, speaking strictly in regard to the standard, we can say it is
correct, since it is explicitly mentioned there.
No, it means that the output of the program must not rely on the order of
the bit-fields.


No, it means that the output of the program must not rely on their being
able to store values outside the minimum guaranteed range.

OK, a strictly conforming program can't rely on the order of bit-
fields or on integer ranges other than those guaranteed. But, does
that mean that such a program would be incorrect? For example:

#include <stdio.h>
#include <limits.h>

int main(void)
{
int i = 0;

#if INT_MAX >= 33000
i += 33000; // thirty-three thousand
#endif

printf("%d\n" i);
}

According to the horrifying truth I've just learned, this program
isn't conforming (the standard only guarantees that 'int' can
represent up to 32767), but it will never fail. Is this program
"incorrect" according to the standard?
Alternative forms of main (other than those mandated by the Standard) *do*
constitute an extension, and one that no implementor is obliged to
provide.

But void main(void) *is* mandated by the standard, at the line where
it mentions "or in some other implementation-defined manner". Thus,
accepting void main(void) does not constitute an extension.

Sebastian
 
K

Keith Thompson

(e-mail address removed) said: [...]
So far, the bottom line remains the same: it *is* correct; it simply
isn't guaranteed to work on every compiler.

It seems that we have a terminology disagreement again. I don't see it as
being "correct". I know it fails on at least two implementations that I
use regularly.

But, speaking strictly in regard to the standard, we can say it is
correct, since it is explicitly mentioned there.

Where are you getting your odd ideas about the meaning of the word
"correct"?

In C99 5.1.1.3, the standard explicitly mentions "a translation unit
containing a violation of any syntax rule or constraint". Does
that make such a translation unit "correct"?

Note that an implementation is allowed to translate and execute such a
program; it just has to issue a diagnostic message.

I can write this:

void main(void) { }

and feed it to a conforming C compiler, and that compiler is allowed
to reject it, or to accept it and generate code that causes *anything*
to happen. If you call that "correct", then I suggest you choose a
different word; the rest of us don't use it the way you do.

There is a valid point here. An implementation is *allowed* to
support the above definition of main(), and to define what it does.
Most likely the program does nothing. So the above program is
"correct" *only with respect to any particular implementation that
supports it*. The standard says so, though not quite in so many
words.

Saying that "void main(void) { }" is "correct", without any further
qualification, is just plain wrong. (Saying that it's "incorrect" is
also arguably wrong. Saying that it's stupid, on the other hand, is
fine with me.)

[...]
OK, a strictly conforming program can't rely on the order of bit-
fields or on integer ranges other than those guaranteed. But, does
that mean that such a program would be incorrect? For example:

#include <stdio.h>
#include <limits.h>

int main(void)
{
int i = 0;

#if INT_MAX >= 33000
i += 33000; // thirty-three thousand
#endif

printf("%d\n" i);
}

According to the horrifying truth I've just learned, this program
isn't conforming (the standard only guarantees that 'int' can
represent up to 32767), but it will never fail. Is this program
"incorrect" according to the standard?

Yes, it's conforming. The standard defines the terms "conforming" and
"strictly conforming" *very* differently.

C99 4p3:

A program that is correct in all other aspects, operating on
correct data, containing unspecified behavior shall be a correct
program and act in accordance with 5.1.2.3.

[...]
But void main(void) *is* mandated by the standard, at the line where
it mentions "or in some other implementation-defined manner". Thus,
accepting void main(void) does not constitute an extension.

"int main(void)" is mandated by the standard, in the sense that any
conforming hosted implementation must support it.

"void main(void)" is not mandated by the standard.

To a programmer, though, it shouldn't really matter whether
"void main(void)" is correct or incorrect, valid or invalid, legal, or
illegal, conforming or non-conforming, or whatever term you want to
use. It is less portable than "int main(void)", and has *no*
compensating advantage over it. The whole issue can be easily avoided
just by using "int main(void)" and not "void main(void)".
 
S

s0suk3

C&V, please. Where does the Standard explicitly say that void main(void) is
"correct"? Indeed, where does the Standard explicitly mention void
main(void) at all?

It is implied by "or in some other implementation-defined manner" in
5.1.2.2.1. Perhaps that's not as explicit as it would be if it clearly
stated something like "main shall be defined as void main(void)", but
at least it's more explicit than simply allowing it to be accepted as
an extension (or as a result of UB).

Given that wording in 5.1.2.2.1, we can now think of it as "correct"
and not necessarily as UB, even though it will yield correct results
in some implementations and UB in others.
No. A program doesn't have to be strictly conforming to be correct. The
Standard doesn't define "correct", of course, so we have to assume that
the ordinary meaning applies, and your code:

 For example:

[Fixed missing comma.]
looks fine to me provided one is using C99 rules. In C89, it's incorrect.


Yes, it is. It isn't *strictly* conforming, but it is conforming.

And the only difference between that example and one that contains
void main(void) is that here we're providing a check so that we won't
overflow 'i'. There is no way to check if the compiler recognizes void
main(void), but such is also the case for bit-fields ordering and
perhaps other features I can't think of right now.

So do you agree now that void main(void) it *is* correct, and that
even though it can't be used in a "strictly conforming" program, it
can be used in a "conforming" one?

<snip>

Sebastian
 
K

Keith Thompson

It is implied by "or in some other implementation-defined manner" in
5.1.2.2.1. Perhaps that's not as explicit as it would be if it clearly
stated something like "main shall be defined as void main(void)", but
at least it's more explicit than simply allowing it to be accepted as
an extension (or as a result of UB).

You are wrong.

A statement like "main shall be defined as void main(void)" (which
doesn't occur in the standard) has a completely different meaning than
the "or in some other implementation-defined manner" that actually
does occur in the standard. It's not just more or less explicit, it's
a *different statement*.
Given that wording in 5.1.2.2.1, we can now think of it as "correct"
and not necessarily as UB, even though it will yield correct results
in some implementations and UB in others.

By the same reasoning, we can now thing if it as UB and not
necessarily as "correct", even though it will invoke UB in some
implementations and be "correct" in others.

[...]
And the only difference between that example and one that contains
void main(void) is that here we're providing a check so that we won't
overflow 'i'.

Um, there's also the fact that one uses "void main(void)" and the
other doesn't.
There is no way to check if the compiler recognizes void
main(void), but such is also the case for bit-fields ordering and
perhaps other features I can't think of right now.

C99 4p8:

An implementation shall be accompanied by a document that defines
all implementation-defined and locale-specific characteristics and
all extensions.

So you can check whether a compiler recognizes void main(void) by
reading its documentation.
So do you agree now that void main(void) it *is* correct, and that
even though it can't be used in a "strictly conforming" program, it
can be used in a "conforming" one?

You're right that it can't be used in a strictly conforming program
and that it can be used in a conforming one. If you'll look at the
standard, you'll understand that the meaning of a "conforming program"
is almost uselessly broad. And no, I absolutely do not agree that
void main(void) is "correct".

What point are you really trying to make here, anyway? This entire
debate seems to be about the meaning of the word "correct", not about
the C language. Are you arguing just for the sake of arguing, or is
there some point to all this? Is there any real disagreement about
what the standard says, or are just playing word games?

You do understand, don't you, that some implementations allow
"void main(void)" and others don't, but that all hosted
implementations allow "int main(void)"? I don't think you've
explicitly advocated using "void main(void)" in real code; do you
think it should be used? If so, why? If not, why are you so
interested in attempting to prove that it's "correct"?
 
K

Kenny McCormack

Keith Thompson <[email protected]> proved what we've been saying all along
(though no mention yet about [not] casting the return value of malloc()):
....
To a programmer, though, it shouldn't really matter whether
"void main(void)" is correct or incorrect, valid or invalid, legal, or
illegal, conforming or non-conforming, or whatever term you want to
use. It is less portable than "int main(void)", and has *no*
compensating advantage over it. The whole issue can be easily avoided
just by using "int main(void)" and not "void main(void)".

Doing what CLC regs do best...

P.S. Suppose that on my implementation (which happens to be an embedded
system running an ATM), void main(void) causes cash to come out of the
machine ($700 billion dollars worth, ...), but int main(void) generates
no such benefit. I'd say that's a "compensating advantage" to using
void main(void). I believe the standard allows this behavior.
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top