Sunday, February 11, 2018

Digest for comp.lang.c++@googlegroups.com - 3 updates in 2 topics

Lynn McGuire <lynnmcguire5@gmail.com>: Feb 11 04:27PM -0600

xkcd, "The History of Unicode"
https://xkcd.com/1953/
 
Lynn
David Brown <david.brown@hesbynett.no>: Feb 11 04:16PM +0100

On 09/02/18 18:48, James Kuyper wrote:
> that could only come up because that construct was permitted: the
> possibility of forgetting to #include the appropriate header, and
> getting no warning about the declaration being missing.
 
I realise that. And I can understand the reasoning for worrying about
accidentally using undeclared functions in 1987. I can't understand
worrying about it now, because tools will detect it. Even if you have
to use an older or more limited compiler (and sometimes you do), you can
use additional tools for checking. Many editors will do it.
 
> C90. Modern implementation that have a C90 mode often warn about this,
> but it's still often optional, and was not as common before C99 came out
> as it is now.
 
C99 came out /long/ ago. Yes, there are still C90-only compilers in
use. Yes, there are compilers with limited warnings in use. There can
be a number of reasons why you need to compile code with tools that have
little or no ability to spot such errors. I have occasion to use these
sorts of tools myself when making changes to old projects.
 
But there is a big difference between what you need to use while
/building/ code, and what you can use while /developing/ code. Your
build environment might consist of an ancient C90 compiler, because that
is the one that is tested and qualified for the project. Or it might
consist of a new C90-only compiler, because that is the only one that
exists for the weird processor you are using. Or you might have no idea
about the build environment because there are thousands of people using
the code with all sorts of tools and flags.
 
However, as the developer, /you/ control the development environment.
/You/ choose to use a smart editor/IDE that checks as you go along, or
run pc-lint, or clang-analyzer, or whatever. /You/ choose to have
standards that you follow, common development patterns, standard headers
that you always use, code reviews with colleagues, etc.
 
You might, for many reasons, not have a build process that makes it easy
to catch mistakes like missing function declarations. But there are so
many ways to catch it as part of the development process that it is not
something to code around - not for development /today/ at least. Twenty
years ago, maybe even ten years ago, you could argue that omitting the
cast on malloc lead was a code safety point - not now.
 
> vitriol against those who object to it would be more understandable. But
> I know of none, (and I've heard the faulty arguments of those who think
> it makes their code safer a great many times).
 
I am only arguing here that the code safety reason for not casting
malloc is a moot point - you can have other good reasons. Personally, I
use malloc so rarely that I can't really say whether I would use a cast
or not. For example, I believe the cast /does/ add to code safety if
the pointer definition was far from the malloc call - but I would also
say it is usually much better to put the pointer definition at the
malloc call (to initialise the pointer), negating that point. The
overriding issue for me is to decide what makes code clearer, and I
don't think a categorical answer can be made. (The exception is if the
code needs to be compiled as C++, in which case there is only one
possible choice - use the cast.)
 
 
> the construct, and not getting any warning about the fact.
> It's also about not writing code that serves no useful purpose, and that
> applies even to more modern C compilers.
 
I agree that you should not write code that serves no useful purpose. I
don't agree that the cast necessarily is without purpose.
 
 
>> I don't see casting malloc()s as a mistake.
 
> That's too bad - you really should understand the reasons why it was (in
> C90). It's an important example of how not to design a computer language.
 
I am not sure I follow you. I understand why C allows void* to be
converted without a cast. I understand why C++ does not allow that, and
why such implicit conversions are a bad idea (along with many other
"implicit" things in C, such as "implicit int".) And I understand why
it was reasonable to think that omitting a cast on malloc results was a
safety point in C coding long ago. I simply don't agree that it is a
relevant safety point /now/, even for C90 programming.
 
> it). It's getting the right size - and that's something that can be
> arranged perfectly by using malloc(count * sizeof *p), without needing
> to know or care about what type *p is.
 
I appreciate that idiom, and it can be useful at times - but it is
certainly not the only way to allocate memory. And if the omission of
the cast makes such code clearer, less repetitive and has lower risk of
error, then I entirely agree - omit the cast in such cases. But if you
have a different arrangement for your malloc and the cast makes the code
clearer or safer, then use it.
 
And if you don't know or care what type *p is, why are you using it in
the first place?
James Kuyper <jameskuyper@verizon.net>: Feb 11 01:33PM -0500

On 02/11/2018 10:16 AM, David Brown wrote:
> On 09/02/18 18:48, James Kuyper wrote:
>> On 02/09/2018 12:10 PM, David Brown wrote:
...
> I realise that. And I can understand the reasoning for worrying about
> accidentally using undeclared functions in 1987. I can't understand
> worrying about it now, because tools will detect it.
 
[Note to others reading this message: since this discussion is occurring
on comp.lang.c++, it might seem odd, but this part of the discussion has
actually been about the behavior of malloc() under C, not about
std::malloc() under C++. Thread drift - sorry. Under C++, a cast is
unambiguously required, and that is not a point under contention.]
 
It isn't a significant worry now. But because it takes EXTRA effort to
insert the cast, with no associated benefit, the insignificant worry
about the possibility of the code getting compiled as C90 should be more
than sufficient to tip the scale.
 
> use malloc so rarely that I can't really say whether I would use a cast
> or not. For example, I believe the cast /does/ add to code safety if
> the pointer definition was far from the malloc call - but I would also
 
It doesn't. No matter how far away the declaration is from the point of
use, you can be quite certain that if the following line compiles
without a diagnostic, then
 
p = malloc(count * sizeof *p);
 
will either result in p containing a null pointer, or pointing at a
block of memory sufficiently large to to contain 'count' objects of
whatever type p points at. Inserting the cast only creates an error if
the type of *p is changed, an error that would not have been an error if
the cast had not been inserted. It's a trivially identified and
corrected error, but that correction is unnecessary extra work created
by insertion of an unnecessary cast.
 
...
> converted without a cast. I understand why C++ does not allow that, and
> why such implicit conversions are a bad idea (along with many other
> "implicit" things in C, such as "implicit int".) ...
 
That isn't an "other ... thing". This is one aspect of "implicit int":
undeclared functions were implicitly declared as returning "int", and
that's precisely the feature I was referring to when I said this was "an
important example of how not to design a computer language". It's
important because the problem is subtle: well-chosen default behavior
generally makes things easier to use - but this particular default was
not well-chosen, because it made things more dangerous; understanding
why is something a language designer should learn.
 
> it was reasonable to think that omitting a cast on malloc results was a
> safety point in C coding long ago. I simply don't agree that it is a
> relevant safety point /now/, even for C90 programming.
 
People (not many) are still using compilers that either don't warn about
this, or need to have options turned on to warn about it, and many of
those users are unaware of the desirability of doing so. If there's any
danger that my code will compiled by such people (possibly after being
cut-and-pasted out of it's normal context), writing it without a cast
both saves me a small amount of typing, and gives them a benefit. If
inserting the cast had any actual benefit (as it does, for instance, in
C++, where it's mandatory), it would be a different matter.
 
...
> error, then I entirely agree - omit the cast in such cases. But if you
> have a different arrangement for your malloc and the cast makes the code
> clearer or safer, then use it.
 
I've seen claims that such situations can occur, and examples that were
intended to support those claims - none of which actually did so.
 
> And if you don't know or care what type *p is, why are you using it in
> the first place?
 
If you're using code involving pointers to 20+ different types (which,
in my experience, isn't particular uncommon), it's convenient to be
justifiably certain that
 
p = malloc(count * sizeof *p);
 
does the correct thing without having to remember or look up which of
those 20+ different types p points at, something that you would be
required to do if it were written with a cast. It's trivial to confirm
that the cast is correct if the malloc() call is the initializer for p,
but in precisely that context, inserting the cast is a particularly
jarring redundancy, not a useful safety measure.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: