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

S

Shao Miller

Well, the thing is, a warning means "you wrote valid C code, but you
used a construction that does something you probably don't want".
However, sometimes I actually know what I'm doing and I refuse to change
my code for the sake of removing a warning if it destroys clarity.

An example is a Microsoft C compiler warning about tagless struct
definitions. One can turn off particular warnings with this compiler,
however.

#define AlignOf_(type_) (offsetof(struct { char c; type_ t; }, t))
 
M

Markus Wichmann

An example is a Microsoft C compiler warning about tagless struct
definitions. One can turn off particular warnings with this compiler,
however.

#define AlignOf_(type_) (offsetof(struct { char c; type_ t; }, t))

You really do use strange stuff! I never encountered the need to know
the alignment of a type yet. Well, at least, whenever I saw it, it was a
crappy micro-optimization with no real value whatsoever (besides, the
compiler can take care of such stuff far better than any human) or a try
to make a structure represent a network packet to the bit, which can be
removed with real unmarshalling.

Ciao,
Markus
 
S

Shao Miller

You really do use strange stuff! I never encountered the need to know
the alignment of a type yet. Well, at least, whenever I saw it, it was a
crappy micro-optimization with no real value whatsoever (besides, the
compiler can take care of such stuff far better than any human) or a try
to make a structure represent a network packet to the bit, which can be
removed with real unmarshalling.

Suppose you have 100 "data drivers" and each one could potentially
interpret some data. If each one of them is handed a 'void *' that
points to the data, well, that's not a lot of information to go on.

Perhaps there's a guarantee that the data is at least one byte, but it'd
be nicer to pass a 'size_t' specifying the size, too. For each driver,
if the size is unsupported, the driver can give up.

Similarly, it'd be nice to pass a 'size_t' (or some other unsigned
integer type) for the alignment, too. For each driver, if the alignment
in unsupported, the driver can give up.

For example, if the data driver tries to interpret the data as:

struct foo {
double d;
int i;
unsigned char sig[5];
};

then it's not particularly safe to simply cast the 'void *' to a pointer
to that type. To be safe, the data would have to be copied from the
'void *'-pointed-to source to some 'struct foo' destination. To be
safe, that copy could only be achieved by knowing how many bytes at the
source (size information). If you're providing size information
already, well you might as well provide alignment information, too.
Then you can even save copying and simply cast.

Of course, that doesn't help with trap representations, so you want to
avoid those and inspect 'sig' first before accessing the 'd' or 'i' members.

Another example is that pre-C99, there weren't "flexible array members"
for 'struct's[n1256: 6.7.2.1p16]. So if you want something that behaves
similarly pre-C99, one option is to concern yourself with the alignment
of some element type.

An example similar to the first would be if you were handed some memory
(other than from 'malloc' and family) to work with and store data into.
If you know what alignment(s) the memory satisfies, you can compute
where in that memory you can access via a given type.
 
T

Tim Rentsch

But it's just enforcing the rules that apply to every other function.

No, the rules for main() are different; that's why they
are described separately.
hdr1.h:
int f(int *x, float y);

hdr2.h:
int f(long *x, double y);

We know that is going to cause trouble, why not warn about it?

If <hdr1.h> and <hdr2.h> are both included in the same
translation unit, a diagnostic must be issued.

If not, I'm still okay with a compiler giving a warning,
especially if there is an option to turn it on or off.
However, saying _a_ compiler _may_ give a warning is very
different from saying _all_ compilers _must_ give a warning.

Moreover, the point for main() is that often we do _not_
know which forms will cause errors and which ones will not.
Furthermore, even if there were an known problem with
form X on platform P, there still is value in allowing
it to be accepted on platform P, because form X may be
perfectly acceptable on platform Q, and all I'm doing is
a test compile.

In short, I'm not opposed to the idea of having a warning
for main(), just opposed to the idea that such a warning be
required at all times for all C compilers.
 
T

Tim Rentsch

Oh I don't think they need any more incentive than they already have. gcc is
a prime example of non-conformance for non-conformance's sake.

That may be true, but whether it is or not I think it's a
bad idea to increase it.
 
K

Keith Thompson

Tim Rentsch said:
In short, I'm not opposed to the idea of having a warning
for main(), just opposed to the idea that such a warning be
required at all times for all C compilers.

So that you can have the benefits of defining main in some non-standard
way without having the compiler complain about it.

Um, what were those benefits again?

If I define main in a way that the compiler I'm using doesn't support,
why would I not want a warning? I didn't advocate a mandatory warning
for non-standard definitions of main *that are supported by the current
compiler*.

My statement from upthread that led to this was:

My own preference would have been to make defining "main"
incorrectly a constraint violation, not undefined behavior.

If an implementation supports "void main(void)", then writing "void
main(void)" would not trigger a mandatory diagnostic (though of course
compilers can warn about anything they like).
 
T

Tim Rentsch

Keith Thompson said:
So that you can have the benefits of defining main in some
non-standard way without having the compiler complain about it.

Um, what were those benefits again?

I think you're assuming that it's always possible, with
relatively little effort, for an implementation to know
whether a particular form of main() is supported by the
target execution environment. For one thing, knowing that
may not always be easy. Moreover, a single compilation may
produce an object file that can be used in several target
execution environments, and the rules for main() in those
environments may differ from one to another. I don't think
people should be forced to compile a program multiple times,
with different sets of compiler options, just because, eg,
the result is going to be run on several different *nix
variants with different rules about which forms of main()
will work.

If I define main in a way that the compiler I'm using doesn't
support, why would I not want a warning?

The relevant question is not whether you would want a warning but
whether everyone should get one in all circumstances. Basically
you would be imposing your stylistic preferences on everyone
else. If someone's stylistic preferences are going to be imposed
on everyone else. the preferences being imposed naturally should
be my preferences, not yours. Right? :)
I didn't advocate a mandatory warning for non-standard
definitions of main *that are supported by the current
compiler*.

Again I think you're assuming that this is always relatively
easy to know and also that a single compilation is targeting
only homogeneous execution environments as regards main().
I don't think either of those is necessarily true.

My statement from upthread that led to this was:

My own preference would have been to make defining "main"
incorrectly a constraint violation, not undefined behavior.

If an implementation supports "void main(void)", then writing
"void main(void)" would not trigger a mandatory diagnostic
(though of course compilers can warn about anything they like).

I understand -- although you don't say it this way, you would
prefer to impose your idea of a particular diagnostic situation
on all other people who use C compilers. Speaking as one of
those other people, I don't want it, for reasons I have partially
explained above. I'm not opposed to /you/ getting a diagnostic
message if you want one, as long as it doesn't interfere with my
choice about whether /I/ get one (and likewise for other people).
The situation for main() just doesn't seem compelling enough or
universal enough to impose a single decision on every developer
in every compilation.
 
K

Keith Thompson

Tim Rentsch said:
I think you're assuming that it's always possible, with
relatively little effort, for an implementation to know
whether a particular form of main() is supported by the
target execution environment. For one thing, knowing that
may not always be easy. Moreover, a single compilation may
produce an object file that can be used in several target
execution environments, and the rules for main() in those
environments may differ from one to another. I don't think
people should be forced to compile a program multiple times,
with different sets of compiler options, just because, eg,
the result is going to be run on several different *nix
variants with different rules about which forms of main()
will work.

All conforming (hosted) C implementations support "int main(void)"
and "int main(int argc, char *argv[])".

My question was, what are the benefits of defining main in some way
other than those two? I don't see an answer to that.
The relevant question is not whether you would want a warning but
whether everyone should get one in all circumstances. Basically
you would be imposing your stylistic preferences on everyone
else. If someone's stylistic preferences are going to be imposed
on everyone else. the preferences being imposed naturally should
be my preferences, not yours. Right? :)


Again I think you're assuming that this is always relatively
easy to know and also that a single compilation is targeting
only homogeneous execution environments as regards main().
I don't think either of those is necessarily true.

Yes, I'm assuming that a given compiler knows what forms of main are
supported by that compiler. That's not *necessarily* true; the same
compiler could be used both for a target that supports "double
main(char*)" and for one that doesn't. In effect, the same compiler
would be part of two distinct implementations.

But in such a case, it shouldn't be at all difficult to parameterize the
compiler so that it *does* know what forms of main are supported.
There's no reason a single compiler can't produce different diagnostics
when invoked for different targets.

And I don't know of any such implementations anyway. Do you?

The scenario you seem to be advocating is this:

I write a non-standard definition for "main", perhaps out of
ignorance. The implementation I am using does not support that
particular definition; my program's behavior is therefore undefined.
The compiler does not warn me about this.

You really see some benefit in that behavior?
I understand -- although you don't say it this way, you would
prefer to impose your idea of a particular diagnostic situation
on all other people who use C compilers. Speaking as one of
those other people, I don't want it, for reasons I have partially
explained above. I'm not opposed to /you/ getting a diagnostic
message if you want one, as long as it doesn't interfere with my
choice about whether /I/ get one (and likewise for other people).
The situation for main() just doesn't seem compelling enough or
universal enough to impose a single decision on every developer
in every compilation.

I also want diagnostics for syntax errors, missing headers,
undeclared identifiers, and so forth. These diagnostics are required
by the language, and I presume you don't object to that.

I fail to see how using a definition of main *that is not supported
by the compiler I'm using* should be any different.

But if you don't want such a warning, you could always filter it
out or invoke the compiler in some non-conforming mode.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
[...]
In short, I'm not opposed to the idea of having a warning
for main(), just opposed to the idea that such a warning be
required at all times for all C compilers.

So that you can have the benefits of defining main in some
non-standard way without having the compiler complain about it.

Um, what were those benefits again?

I think you're assuming that it's always possible, with
relatively little effort, for an implementation to know
whether a particular form of main() is supported by the
target execution environment. For one thing, knowing that
may not always be easy. Moreover, a single compilation may
produce an object file that can be used in several target
execution environments, and the rules for main() in those
environments may differ from one to another. I don't think
people should be forced to compile a program multiple times,
with different sets of compiler options, just because, eg,
the result is going to be run on several different *nix
variants with different rules about which forms of main()
will work.

All conforming (hosted) C implementations support "int main(void)"
and "int main(int argc, char *argv[])".

My question was, what are the benefits of defining main in some way
other than those two?

I didn't get that sense reading the previous posting, and reading
it over again, I still don't. But I will ignore that and address
the question as you restated it.
I don't see an answer to that.

That seems obvious - a fair number of implementations choose to do so,
both historically and (I assume) currently, because the implementors
believe there is value in doing so. Before C was standardized I was
used to a three argument form of main(), and I'm sure many other
people were as well. I'm not going to try to give examples; I think
the existence of implementations that avail themselves of the allowed
flexibility is evidence enough.

Yes, I'm assuming that a given compiler knows what forms of main are
supported by that compiler. That's not *necessarily* true; the same
compiler could be used both for a target that supports "double
main(char*)" and for one that doesn't. In effect, the same compiler
would be part of two distinct implementations.

I simply disagree with the assumption. I think it's much harder
than you seem to think it is.
But in such a case, it shouldn't be at all difficult to parameterize the
compiler so that it *does* know what forms of main are supported.

First, I disagree with your assessment. Second, my point is
that the cost of requiring it of ALL implementations outweighs
the benefit. The cost is non-trivial; the benefit is trivial.
There's no reason a single compiler can't produce different diagnostics
when invoked for different targets.

And I don't know of any such implementations anyway. Do you?

You're assuming that a compiler always knows exactly for which
target it is being invoked, and that it is always invoked
separately for different targets. I believe both of these
assumptions are wrong.
The scenario you seem to be advocating is this:

I write a non-standard definition for "main", perhaps out of
ignorance. The implementation I am using does not support that
particular definition; my program's behavior is therefore undefined.
The compiler does not warn me about this.

I'm not advocating any particular compiler use case. I
believe allowing such use cases has value, but more to
the point disallowing them has relatively little value
but non-trivial costs. The ROI is negative.
You really see some benefit in that behavior?

There are cases where such use cases have value, yes. But
that belief is incidental to my main point.

I also want diagnostics for syntax errors, missing headers,
undeclared identifiers, and so forth. These diagnostics are required
by the language, and I presume you don't object to that.

I fail to see how using a definition of main *that is not supported
by the compiler I'm using* should be any different.

Here is an important difference. The other cases you mention all
depend on things that are completely under the implementation's
control. Because the implementation has total knowledge, it's
easy for it to give diagnostics in precisely those circumstances
that cause problems. The possible forms of main() depend on
things that are outside the implementation's control, and may
change over time, and indeed may be unknown (or potentially even
unknowable) to the implementation. Therefore it is more
difficult, and in some cases conceivably impossible, for the
implementation to know precisely which circumstances are going
to cause problems.
But if you don't want such a warning, you could always filter it
out or invoke the compiler in some non-conforming mode.

Since you're the person who's proposing a change, it's up
to you to convince other people it's a good idea. Telling
me I'm going to have to do more work so we get something
that I think doesn't have much value in the first place
does not convince me, and in fact very much the opposite.
 
K

Keith Thompson

Tim Rentsch said:
I simply disagree with the assumption. I think it's much harder
than you seem to think it is.

It would be helpful if you could cite a specific implementation where
this would be at all difficult. I've never encountered one.

[...]
 
J

jacob navia

Le 09/03/12 22:36, Keith Thompson a écrit :
Tim Rentsch said:
I simply disagree with the assumption. I think it's much harder
than you seem to think it is.

It would be helpful if you could cite a specific implementation where
this would be at all difficult. I've never encountered one.

[...]

In the adaptation of my compiler system to an embedded 16 bit processor
I used

void main(void);

since the main routine never exited, so it never returned a result.

In the same spirit it didn't receive any arguments since it is called
by nothing: when powered on, the circuit starts the main function
automatically.

But here we go: thompson is AGAIN for the millionth time speaking about
the syntax of the "main" function, a trivial pursuit that he is drowning
us since several YEARS.

I have lost count. Those are the evergreens of this boring group that
he represents so well.

The other guy (rentsch) wakes up every months or so and revives old
dead threads with small remarks without any content and engages with
thompson in those ah so important discussions.


int main(void);
or
int main(int foo,char*bar[]);

Go on gentlemen, just go on
 
T

Tim Rentsch

Keith Thompson said:
It would be helpful if you could cite a specific implementation where
this would be at all difficult. I've never encountered one.

It isn't my goal to convince you. Again, since you
are the one proposing a change, the onus of convincing
others is on you, not them. ISTM that all you've done
is state your opinion that it's easy (or not very
difficult). My opinion is different.
 
K

Keith Thompson

Tim Rentsch said:
It isn't my goal to convince you. Again, since you
are the one proposing a change, the onus of convincing
others is on you, not them. ISTM that all you've done
is state your opinion that it's easy (or not very
difficult). My opinion is different.

You've also stated a definite opinion, that it can be difficult for
a compiler to decide which forms of main it supports. You don't
*have* to support that opinion, but if you don't I'll just continue
to think that you're mistaken.
 
K

Kenny McCormack

Kiki Thompson said:
You've also stated a definite opinion, that it can be difficult for
a compiler to decide which forms of main it supports. You don't
*have* to support that opinion, but if you don't I'll just continue
to think that you're mistaken.

Well, Tim, I guess you can just pack it in now.

I can't imagine life is worth living anymore - now that King Kiki has given
up on your re-education..

--
"The anti-regulation business ethos is based on the charmingly naive notion
that people will not do unspeakable things for money." - Dana Carpender

Quoted by Paul Ciszek (pciszek at panix dot com). But what I want to know
is why is this diet/low-carb food author doing making pithy political/economic
statements?

Nevertheless, the above quote is dead-on, because, the thing is - business
in one breath tells us they don't need to be regulated (which is to say:
that they can morally self-regulate), then in the next breath tells us that
corporations are amoral entities which have no obligations to anyone except
their officers and shareholders, then in the next breath they tell us they
don't need to be regulated (that they can morally self-regulate) ...
 
J

jacob navia

Le 10/03/12 01:57, Kenny McCormack a écrit :
Well, Tim, I guess you can just pack it in now.

I can't imagine life is worth living anymore - now that King Kiki has given
up on your re-education..
Yes, I am considering suicide since he said that I was in his killfile

:)
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
[...]
Yes, I'm assuming that a given compiler knows what forms of main are
supported by that compiler. That's not *necessarily* true; the same
compiler could be used both for a target that supports "double
main(char*)" and for one that doesn't. In effect, the same compiler
would be part of two distinct implementations.

I simply disagree with the assumption. I think it's much harder
than you seem to think it is.

It would be helpful if you could cite a specific implementation where
this would be at all difficult. I've never encountered one.

It isn't my goal to convince you. Again, since you
are the one proposing a change, the onus of convincing
others is on you, not them. ISTM that all you've done
is state your opinion that it's easy (or not very
difficult). My opinion is different.

You've also stated a definite opinion, that it can be difficult for
a compiler to decide which forms of main it supports. You don't
*have* to support that opinion, but if you don't I'll just continue
to think that you're mistaken.

It seems like you aren't interested in making an effort
to convince others of your opinion. If you aren't going
to make such an effort, I don't see why I should, even
ignoring the other point that it's you who is advocating
a change in the first place. You first.
 
K

Keith Thompson

Tim Rentsch said:
It seems like you aren't interested in making an effort
to convince others of your opinion. If you aren't going
to make such an effort, I don't see why I should, even
ignoring the other point that it's you who is advocating
a change in the first place. You first.

I stated my reasons several months ago.

This isn't important enough for me to spend any more time arguing
about it.

Your claim, that it can be difficult for a compiler to determine
what forms of main() it should support, is an interesting one.
As I said, I've never encountered such a situation. I was hoping
both to learn something and to advance this discussion.

I understand that it's theoretically possible that a compiler might
have difficulty determining what forms of main() are supported on the
target system for which it's generating code. I do not believe that
there is any such difficulty in practice. I'll just leave it at that.

(What I *really* would have preferred would be for any definition of
main() other than the two standard ones to be a constraint violation.
Compilers could still support other forms as an extension and/or in
some non-conforming mode. That *might* have prevented the endless
arguments over "void main()", with no great cost that I can see.
I know about the third "envp" parameter; as I said, that could still
be implemented, but with a diagnostic or in non-conforming mode.
To be clear, I'm talking about a hypothetical change that *could*
have been made by ANSI in 1989, and that would apply only to hosted
implementations.)
 
P

Philip Lantz

Keith said:
It would be helpful if you could cite a specific implementation where
this would be at all difficult. I've never encountered one.

I use GCC to generate code for both a standard Linux platform, and for
an embedded system. I use the exact same GCC for both cases. In the
latter case, main is called by startup code that I have written in
assembly language. GCC has *no idea whatsoever* what forms of main will
work and which will cause undefined behavior. I doubt very much that
this is an uncommon situation. How do you think GCC could be made to
issue the warning that you suggest should be required?
 
K

Keith Thompson

Philip Lantz said:
I use GCC to generate code for both a standard Linux platform, and for
an embedded system. I use the exact same GCC for both cases. In the
latter case, main is called by startup code that I have written in
assembly language. GCC has *no idea whatsoever* what forms of main will
work and which will cause undefined behavior. I doubt very much that
this is an uncommon situation. How do you think GCC could be made to
issue the warning that you suggest should be required?

When you say you use the exact same GCC, does that imply that you could
take an object file generated by the GCC you're using and use it either
on the Linux platform or on the embedded system? If so, that's not what
I would have expected.

Note that "void main(void)" is not uncommon for embedded systems (i.e.,
freestanding implementations) -- but gcc with "-pedantic" issues a
warning: "return type of 'main' is not 'int'".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,207
Latest member
HelenaCani

Latest Threads

Top