Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Good C programming style

Reply
Thread Tools

Good C programming style

 
 
Sensei
Guest
Posts: n/a
 
      10-08-2005
On 2005-10-07 21:28:50 +0200, "Mike Wahler" <(E-Mail Removed)> said:

> "Sensei" <(E-Mail Removed)> wrote in message
> news:di6gc0$m52$(E-Mail Removed)...
>> Hi!
>>
>> I'm thinking about a good programming style, pros and cons of some
>> topics. Of course, this has nothing to do with indentation... Students
>> are now java-dependent (too bad) and I need some serious motivations
>> for many issues...

>
> So you're teaching C?



Nope. I'm an engineer working on theoretics. I *have* to teach C, and
I'm studying before doing anything wrong.


> but you don't appear able to distinguish C from C++



Correct. I'm trying.


>
> and you don't appear to be aware of the consensus about
> premature optimization



My biggest programming efforts have always been on assembly. I'm used
to do a shift instead of dividing or multiplying by 2. I've read it's
not useful on high level languages like C.

If a variable is passed on the stack, I imagine *i pushes an address,
while i pushed the entire data, so if i is a big structure is not a
nice thing.

Moreover, I don't know if C says *how* parameters are passed to
functions: stack, pointer, whatever...


>
>>
>> - defines: why they use function and variable defines? why they shouldn't?
>> #define MY_PI 3.1415
>> #define fun(x) ((x) * (x))

>
> and you don't appear to be aware of the type-checking that a
> real function can give, and that macros do not.



Of course macros are macros. No checks, no functions. Why using one
instead of another is not clear to me. As I said, I'm an assembly guy,
and ``functions'' do not really exist.

You don't appear to understand that people could ask for informations
here about std-c with different knowledge


--
Sensei <(E-Mail Removed)>

The difference between stupidity and genius is that genius has its
limits. (A. Einstein)

 
Reply With Quote
 
 
 
 
Sensei
Guest
Posts: n/a
 
      10-08-2005
On 2005-10-07 21:35:26 +0200, Skarmander <(E-Mail Removed)> said:

> Sensei wrote:
>> I'm thinking about a good programming style, pros and cons of some
>> topics. Of course, this has nothing to do with indentation... Students
>> are now java-dependent (too bad) and I need some serious motivations
>> for many issues... I hope you can help me I begin with the two major
>> for now, others will come for sure!
>>

> The questions you're asking are elemental. Read a good book on C and
> these topics should be treated in some detail, along with explanations
> that will help you decide on what is appropriate and why.



As I said in another post, I'm studying now.

>
>> given that the function can and cannot (the last case of course) modify
>> a parameter. I see performance issues (stack related)...
>>

> Mostly irrelevant. A C idiom is to always pass structure types by
> pointer because passing most structures by value means copying, which
> is indeed a waste of time in most cases, especially if the value isn't
> modified. While a compiler could optimize this in some cases, it's not
> expected to, and programmers don't count on it.



Clear.


>
>> - defines: why they use function and variable defines? why they shouldn't?
>> #define MY_PI 3.1415

>
> Established C practice is to use #define for constants since C is a bit
> puzzling when it comes to constants. Declaring a variable "const" does
> not make its value a constant expression for purposes of array sizes,
> for example. Also, memory is allocated for const variables (great
> oxymoron, incidentally when it typically isn't necessary.
>
> There's no such thing as a "function" or "variable" define, however.
> Macros just establish textual replacement rules.



Yes but...

>
>> #define fun(x) ((x) * (x))
>>

> Use functions when you can, macros when you have to. The example above
> is a case of when you don't have to.
>
> As for when you need macros, that's not a matter of coding style.


....this is puzzling to me. I've seen functions replaced by macros, like this:

#define xge_mklink_slot(com,from,to,slotfrom,slotto) \
{\
tkey _slotfrom=(slotfrom);\
tkey _slotto =(slotto );\
\
CHECKPOINT("ie",getcell((com),(from)).level!=0xff &&
getcell((com),(to)).level!=0xff);\
\
if (!_slotfrom)\
{\
if (!(com)->memlink.freelist) realloc_link((com));\
_slotfrom=(com)->memlink.freelist;\
(com)->memlink.freelist=getlink((com),_slotfrom).next; \
++((com)->memlink.num);\
\
if (!getcell((com),(from)).nup)\
getcell((com),(from)).firstup=_slotfrom;\
else\

getlink((com),getcell((com),(from)).lastup).next=_ slotfrom;\
\
getlink((com),_slotfrom).next=0;\
getlink((com),_slotfrom).prev=getcell((com),(from) ).lastup; \
getcell((com),(from)).lastup=_slotfrom;\
++getcell((com),(from)).nup;\
}\
\
if (!_slotto)\
............


So, I was wondering why and when it's a good idea to use defines.


--
Sensei <(E-Mail Removed)>

The difference between stupidity and genius is that genius has its
limits. (A. Einstein)

 
Reply With Quote
 
 
 
 
Sensei
Guest
Posts: n/a
 
      10-08-2005
On 2005-10-07 21:42:37 +0200, Keith Thompson <(E-Mail Removed)> said:

>
> As for function-like macros, they're sometimes the best way to create
> inline functions. (C99 has inline functions, but not all compilers
> support them.) There are also things you can do in a macro that you
> can't easily do in a function, such as using a type name as an
> argument. But try not to be too tricky. Macros can be dangerous,
> since they're expanded in a very early stage of compilation. They can
> *look* like function calls or variable declarations, but they don't
> necessarily act like them; for example, they pay no attention to scope.



Ok, so defines are used to improve performances as inline functions are
not supported everywhere.


--
Sensei <(E-Mail Removed)>

The difference between stupidity and genius is that genius has its
limits. (A. Einstein)

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-08-2005
pete <(E-Mail Removed)> writes:
> Keith Thompson wrote:
>> const double my_pi = 3.14159265358979323848264;

>
> Where the hell did you get the idea that the next digit after
> 3.1415926535897932384 was 8?!!!
>
>


Oops, I meant 6 of course.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
 
Reply With Quote
 
Richard Heathfield
Guest
Posts: n/a
 
      10-08-2005
Gregory Pietsch said:

> Sensei wrote:
>
>> #define MY_PI 3.1415

>
> You might want to extend pi a few more decimal places.


Why? Observe:

Circumference of Earth (plus or minus a bit): 40000000 metres.
Pi = 3.1415
Radius of Earth: 6366385 metres

Let's add 1 dp.

Circumference of Earth (plus or minus a bit): 40000000 metres.
Pi = 3.14159
Radius of Earth: 6366203 metres

Difference from last result: 182 metres. If you're calculating fuel
requirements for a trip round the entire planet, you'd factor in a
contingency anyway; you're not going to crash for the sake of 182 metres.

Let's add another.

Circumference of Earth (plus or minus a bit): 40000000 metres.
Pi = 3.141592
Radius of Earth: 6366199 metres

Difference from last result: 4 metres. Good enough for nuclear war.

Let's add another.

Circumference of Earth (plus or minus a bit): 40000000 metres.
Pi = 3.1415926 (still comfortably within the ability of a pocket calculator)
Radius of Earth: 6366198 metres. Difference from last result: 1 metre. Good
enough for assassinating one mad dictator (or one troublesome priest) from
the other side of the planet.

Let's add another.

Circumference of Earth (plus or minus a bit): 40000000 metres.
Pi = 3.14159265
Radius of Earth: 6366198 metres. Difference from last result: 0 metres.
(Okay, so I'm rounding - but the difference is less than 1 metre, that's
the point.)

So who gives a stuff?


--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/2005
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      10-08-2005
Keith Thompson wrote:
>
> pete <(E-Mail Removed)> writes:
> > Keith Thompson wrote:
> >> const double my_pi = 3.14159265358979323848264;

> >
> > Where the hell did you get the idea that the next digit after
> > 3.1415926535897932384 was 8?!!!
> >
> >

>
> Oops, I meant 6 of course.


I've waited over two years for a chance to use that line again.

http://groups.google.com/group/comp....5e5b2a7f8e39ab

Thank you.

--
pete
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-08-2005
pete <(E-Mail Removed)> writes:
> Keith Thompson wrote:
>> pete <(E-Mail Removed)> writes:
>> > Keith Thompson wrote:
>> >> const double my_pi = 3.14159265358979323848264;
>> >
>> > Where the hell did you get the idea that the next digit after
>> > 3.1415926535897932384 was 8?!!!
>> >
>> >

>>
>> Oops, I meant 6 of course.

>
> I've waited over two years for a chance to use that line again.
>
> http://groups.google.com/group/comp....5e5b2a7f8e39ab
>
> Thank you.


You're welcome. Had I known, I might have made the mistake
intentionally. }

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
 
Reply With Quote
 
Flash Gordon
Guest
Posts: n/a
 
      10-08-2005
Sensei wrote:
> On 2005-10-07 21:28:50 +0200, "Mike Wahler" <(E-Mail Removed)> said:
>
>> "Sensei" <(E-Mail Removed)> wrote in message
>> news:di6gc0$m52$(E-Mail Removed)...
>>
>>> Hi!
>>>
>>> I'm thinking about a good programming style, pros and cons of some
>>> topics. Of course, this has nothing to do with indentation...
>>> Students are now java-dependent (too bad) and I need some serious
>>> motivations for many issues...

>>
>> So you're teaching C?

>
> Nope. I'm an engineer working on theoretics. I *have* to teach C, and
> I'm studying before doing anything wrong.


Well, I hope you have plenty of time, since you have a *lot* to learn.

>> but you don't appear able to distinguish C from C++

>
> Correct. I'm trying.


Try to learn one language at a time. Trying to learn two, especially two
with a lot of similarities, is bound to lead to confusion.

>> and you don't appear to be aware of the consensus about
>> premature optimization

>
> My biggest programming efforts have always been on assembly. I'm used to
> do a shift instead of dividing or multiplying by 2. I've read it's not
> useful on high level languages like C.


What you have read is correct. Modern compilers have an optimiser to do
this for you.

> If a variable is passed on the stack, I imagine *i pushes an address,
> while i pushed the entire data, so if i is a big structure is not a nice
> thing.


Yes, that is correct. With a large structure you would tend to pass a
pointer to avoid copying a lot of data.

> Moreover, I don't know if C says *how* parameters are passed to
> functions: stack, pointer, whatever...


C does not specify a stack. All it specifies is that parameters are
passed by value (even pointers). On at least some systems parameters
will be passed in registers.

>>> - defines: why they use function and variable defines? why they
>>> shouldn't?
>>> #define MY_PI 3.1415
>>> #define fun(x) ((x) * (x))

>>
>> and you don't appear to be aware of the type-checking that a
>> real function can give, and that macros do not.

>
> Of course macros are macros. No checks, no functions. Why using one
> instead of another is not clear to me. As I said, I'm an assembly guy,
> and ``functions'' do not really exist.


Type checking is a wonderful thing, it allows the compiler to complain
if you do something obviously stupid. Such as passing a pointer to a
function requiring an integer.

> You don't appear to understand that people could ask for informations
> here about std-c with different knowledge


We are quite used to that.

I strongly suggest you work through K&R2 and read the FAQ for this group
(which will explain what K&R2 is).

Also remember that high level languages were invented to make
programming easier, and this means you should forget about using a lot
of the little tricks you use as an assembler programmer.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      10-08-2005
Sensei wrote:

> So, I was wondering why and when it's a good idea to use defines.


If a #define can make the source code easier to read,
then that is why and when.

--
pete
 
Reply With Quote
 
Skarmander
Guest
Posts: n/a
 
      10-08-2005
Sensei wrote:
> On 2005-10-07 21:35:26 +0200, Skarmander <(E-Mail Removed)> said:
>
>> Sensei wrote:
>>

<snip>
>>> #define fun(x) ((x) * (x))
>>>

>> Use functions when you can, macros when you have to. The example above
>> is a case of when you don't have to.
>>
>> As for when you need macros, that's not a matter of coding style.

>
>
> ...this is puzzling to me. I've seen functions replaced by macros, like
> this:
>


> #define xge_mklink_slot(com,from,to,slotfrom,slotto) \
> {\
> tkey _slotfrom=(slotfrom);\
> tkey _slotto =(slotto );\
> \
> CHECKPOINT("ie",getcell((com),(from)).level!=0xff &&
> getcell((com),(to)).level!=0xff);\
> \
> if (!_slotfrom)\
> {\
> if (!(com)->memlink.freelist) realloc_link((com));\
> _slotfrom=(com)->memlink.freelist;\
> (com)->memlink.freelist=getlink((com),_slotfrom).next; \
> ++((com)->memlink.num);\
> \
> if (!getcell((com),(from)).nup)\
> getcell((com),(from)).firstup=_slotfrom;\
> else\
>
> getlink((com),getcell((com),(from)).lastup).next=_ slotfrom;\
> \
> getlink((com),_slotfrom).next=0;\
>
> getlink((com),_slotfrom).prev=getcell((com),(from) ).lastup; \
> getcell((com),(from)).lastup=_slotfrom;\
> ++getcell((com),(from)).nup;\
> }\
> \
> if (!_slotto)\
> ...........
>

This is absolutely horrible. Words fail me. Whoever wrote this should be
shot.

Let's go over why this is a bad idea:

- In a macro, arguments are not checked against their types, as there
are no types. This means that the function is both harder to call ("com"
must be a pointer, but of what type?) and the compiler can offer less
help checking validity.

- Generalizing, the validity of a macro simply cannot be checked on its
own. Only uses of it can be checked. Errors or warnings that occur from
such a use could be either due to bad use or a bad macro, and it'll be
hard to tell which is which.

- Unlike functions, macros use textual replacement for their arguments.
If an argument uses a side-effect (it modifies the program state when
evaluated) then you typically cannot use it. For example:
xge_mklink_slot(c, f++, t++, slf, slt);
This does not have the same effect as the equivalent function call
would: every time "from" is replaced in the macro it is replaced with
"f++". That is, f will be incremented every time "from" is used!

- This is very likely to *harm* performance. Yes, you read that right.
If this macro is invoked multiple times, the great big block of code it
stands for is inserted *every time*. Do this a few times and you'll get
code that is huge. And WHY? Function calls are not nearly as expensive
as most people like to pretend. It is in fact likely this code will run
slower because big code means the instruction cache most modern
processors are equipped with cannot be effectively used. Never try to
outsmart the compiler. Only educate it in things you know it cannot see.
Making decisions on when to inline functions is something a compiler is
qualified to do, and only code profiling should be admissible evidence
to the contrary.

Apropos inlining: almost all compilers I know offer a way to indicate
that inlining is desirable (or even force it where possible). The new
C99 standard adds an "inline" keyword, and most pre-C99 compilers
support an "inline", "_inline", "__inline" keyword or some variation
thereof. Macros are almost never necessary or desirable to get an
inlined function.

All that said, there is one purpose this macro could still serve that
cannot be achieved otherwise in C: precisely because the arguments have
no types, it can be used as a template to produce similar functions that
differ only in the type of the arguments. This is what templates
accomplish in C++ and generics accomplish in the most recent versions of
Java.

But even so, it should only be used in a way that does not compromise
type safety, by defining the type-safe functions:

/* Unlike XGE_MKLINK_SLOT, the compiler will warn or stop if the
argument types do not match the formal parameter types. */
[return-type] xge_mklink_slot(xge_com* com, xge_cell from, xge_cell to,
tkey slotfrom, tkey slotto) {
return XGE_MKLINK_SLOT(com, from, to, slotfrom, slotto);
}

Here [return-type] I cannot know, and the xge_com and xge_cell types are
invented by me. I capitalized XGE_MKLINK_SLOT because macro names
*should* be capitalized to prevent confusion: as I've said, using a
macro is not the same thing as calling a function, and it's dangerous to
pretend that it is.

Even this technique is dubious because xge_mklink_slot is a highly
specific macro, and it's unlikely it's used in the way I sketched above.
Note also that in C, generic functions are usually written by passing
around generic pointers. Consult your C book for more information; it
will probably mention the qsort() function as an example.

This macro *should* be rewritten to a function. I cannot conceive of any
reason why a macro would be preferrable in this case. Do you understand
why I said it's not a matter of coding style? It's a matter of what you
want to achieve, not how it looks. "Style", if it comes into play at
all, is to prefer functions to macros consistently, and being ready to
justify your use of a macro.

> So, I was wondering why and when it's a good idea to use defines.
>

Don't think in terms of "good idea/bad idea". Learn what purpose and
what drawbacks each feature has, then apply this knowledge in every case
to achieve the best result. In case of macros, the drawbacks associated
with them very often outweigh the benefits, especially when it comes to
replacing functions.

I can give you the short version, of course, but keep in mind that these
are only rules of thumb and not absolute commandments. Use a macro for:

- defining symbolic constants that are not part of an enumerated type.
Example: #define M_PI 3.1415926536
- encapsulating system-specific constructs that cannot be abstracted by
a function. Example: #define INLINE __inline
- allowing header files to be included more than once without error.
Example:
#ifndef HEADER_H
#define HEADER_H
...contents of "header.h"
#endif

These are the basic established "good ideas" for macros. There are other
circumstances in which experienced C programmers will use macros, but
you should leave them until you can understand why. I won't attempt to
explain it all in a Usenet post; consult the books written by people
who've had more time than me to think about it.

S.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Good idea or gimmick: Go-style OO-programming in C++ ? jeti789@web.de C++ 52 04-06-2013 03:30 AM
Good programming style Astley Le Jasper Python 5 09-15-2008 02:41 PM
good style guides for python-style documentation ? Fredrik Lundh Python 4 04-07-2006 06:19 AM
Could you tell me if this is good meta programming style? Vincent Foley Ruby 2 04-29-2005 10:31 PM
Need help with Style conversion from Style object to Style key/value collection. Ken Varn ASP .Net Building Controls 0 04-26-2004 07:06 PM



Advertisments