Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #154103
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Newsgroups | comp.lang.c |
| Subject | Re: "Why the C Language Will Never Stop You from Making Mistakes" by JeanHeyd Meneide |
| Date | 2020-08-28 08:10 -0700 |
| Organization | A noiseless patient Spider |
| Message-ID | <86eenqajr1.fsf@linuxsc.com> (permalink) |
| References | (3 earlier) <rh2475$r12$1@reader1.panix.com> <87r1sb1fu5.fsf@nosuchdomain.example.com> <rh2lpf$5v3$1@reader1.panix.com> <87k0y312ua.fsf@nosuchdomain.example.com> <kD9ZG.114542$mK4.89063@fx03.iad> |
Richard Damon <Richard@Damon-Family.org> writes:
> On 8/13/20 2:23 AM, Keith Thompson wrote:
>
>> John Forkosh <forkosh@panix.com> writes:
>> [...]
>>
>>> I personally do bind the * to the *p_, but would also write it as,
>>> typedef struct Meow meow
>>> meow *p_cat = (meow *)malloc(sizeof(meow));
>>> which is just how I personally like to read and write it.
>>> And if that faq doesn't like it, then it can just go rewrite
>>> itself:)
>>
>> OK, *why* do you like the cast? What is the benefit of it? Why do
>> you think having the cast is better than not having it?
>>
>> You are of course entitled to your opinion, I'm just wondering if
>> you have a basis for it.
>
> The basic argument against the cast is that if you forget the
> include/prototype (which in my opinion, that error should be
> configured to be a fatal errpr) the cast hides that error.
>
> The use of the cast detects if the type of the variable is the
> wrong type of pointer, maybe not as likely in the case where you
> are declaring the pointer, but if you are using an existing
> pointer isn't that hard.
>
> The idiom
>
> p = malloc(sizeof(*p));
>
> also doesn't protect from the 'wrong' type, yes, it will malloc
> for the right type for the pointer, but maybe not for the code
> that is using it.
>
> Using a macro like:
>
>
> #define NEW(T) (T *)malloc(sizeof T)
>
> allows the use of
>
> p = NEW(Foo)
>
> and if p isn't a Foo*, you get an error (or at least a constraint
> violation), and thus you know the code needs to be checked if it
> needs to change based on the new type of *p.
I have read through your postings in this thread on this topic.
Directly put, I disagree with your position and with your
proposal.
There are several factors or principles that argue against the
position. Some of these are:
(1) Casting is bad. Unnecessary casts should be avoided.
(2) It violates the factoring principle. The type name T is
written in several places rather than just once, on the
declaration of the variable assigned the value.
(3) As a consequence of (2), it raises maintenance costs. If a
change in type is needed, the source needs modifying in several
places rather than just one.
(4) As a general rule, we would like to avoid situations that
require multiple parts of a program to be kept "in sync". This
rule is related to (2) but not exactly the same. In some cases
being forced to synchronize two distinct parts of a program has
some benefit, but I don't see any benefit here relative to the
usual idiom `p = malloc( sizeof *p )`.
(5) The reasoning offered has an air (at least it does to me) of
being disingenuous. The concern expressed is not for assigning
to p but later using p to initialize the allocated object. If
the real concern is making sure the initialization matches the
type of *p then that concern should be addressed in the code that
performs the initialization, not the code that does the malloc()
call. There are several ways we might effect such initializing
so that type correctness is ensured:
(1) Have an appropriately typed initializing function:
T *p = malloc( sizeof *p );
initialize_T( p );
(2) Have an appropriately typed value-generating function:
T *p = malloc( sizeof *p );
*p = some_T_value( x, y, z );
(3) Use a compound literal:
T *p = malloc( sizeof *p );
*p = (T){ .foo = 1, .bas = 0, };
In addition to more directly addressing the true concern, these
patterns promote more reliable programming practices.
Turning to the proposal, here is a different one:
#define NEW(p) (p) = malloc( sizeof *(p) )
We can use this pseudo-function as a expression-statement:
T *p;
...
NEW(p);
It also is usable in declarations:
T *NEW(p);
I'm sure some people will react negatively to the declaration
pattern, and that's okay. For those who don't mind it the
pattern is there.
One final comment: although I disagree with some of your
comments I have not set out to persuade or convince anyone
otherwise. My purpose is simply to express my disagreement
and put forth an alternative proposal, for those who may
be interested. I am as always interested to hear whatever
reactions you might have but I'm not here to argue about
which approach is better.
Back to comp.lang.c | Previous | Next | Find similar
Re: "Why the C Language Will Never Stop You from Making Mistakes" by JeanHeyd Meneide Tim Rentsch <tr.17687@z991.linuxsc.com> - 2020-08-28 08:10 -0700
csiph-web