Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

insert-header-preprocessor-definition

3 views
Skip to first unread message

Emanuel Berg

unread,
Apr 11, 2018, 1:36:44 AM4/11/18
to
(defun insert-header-preprocessor-definition ()
(interactive)
(let*((filename (buffer-name))
(label (upcase (replace-regexp-in-string "\\." "_" filename)))
(beg-string (concat
(format "#ifndef %s\n" label)
(format "#define %s\n\n" label) ))
(end-string "\n#endif") )
(save-excursion
(goto-char (point-min))
(insert beg-string)

(goto-char (point-max))
(beginning-of-line)
(insert end-string) )
))
(defalias 'hep #'insert-header-preprocessor-definition)

--
underground experts united
http://user.it.uu.se/~embe8573

Ben Bacarisse

unread,
Apr 11, 2018, 11:47:19 AM4/11/18
to
Emanuel Berg <moa...@zoho.com> writes:

> (defun insert-header-preprocessor-definition ()
> (interactive)
> (let*((filename (buffer-name))
> (label (upcase (replace-regexp-in-string "\\." "_" filename)))

It's off-topic, but this common construction can give rise to C's
dreaded "undefined behaviour". All sorts of macro names are reserved to
the implementation depending on what headers have been included in the
source file that includes this one.

It's common to ignore this rule, but if you are providing a facility for
general use it might be better to follow letter of the law. Pre-pending
"H_" to the label is known to be safe.

> (beg-string (concat
> (format "#ifndef %s\n" label)
> (format "#define %s\n\n" label) ))

I'd probably write

(concat "#ifndef " label "\n"
"#define " label "\n\n")

or if I was not bothered about showing the separate lines:

(format "#ifndef %s\n#define %s\n\n" label label),

<snip>
--
Ben.

Emanuel Berg

unread,
Apr 11, 2018, 4:41:24 PM4/11/18
to
Ben Bacarisse wrote:

> this common construction can give rise to C's
> dreaded "undefined behaviour". All sorts of
> macro names are reserved to the
> implementation depending on what headers have
> been included in the source file that
> includes this one.
>
> It's common to ignore this rule, but if you
> are providing a facility for general use it
> might be better to follow letter of the law.
> Pre-pending "H_" to the label is known to
> be safe.

I agree. So for color.c, color.h should have
H_COLOR_H?

>> (beg-string (concat
>> (format "#ifndef %s\n" label)
>> (format "#define %s\n\n" label) ))
>
> I'd probably write
>
> (concat "#ifndef " label "\n"
> "#define " label "\n\n")

OK!

Ben Bacarisse

unread,
Apr 11, 2018, 4:56:30 PM4/11/18
to
Emanuel Berg <moa...@zoho.com> writes:

> Ben Bacarisse wrote:
>
>> this common construction can give rise to C's
>> dreaded "undefined behaviour". All sorts of
>> macro names are reserved to the
>> implementation depending on what headers have
>> been included in the source file that
>> includes this one.
>>
>> It's common to ignore this rule, but if you
>> are providing a facility for general use it
>> might be better to follow letter of the law.
>> Pre-pending "H_" to the label is known to
>> be safe.
>
> I agree. So for color.c, color.h should have
> H_COLOR_H?

That is safe, yes. Doing it by hand, I think most people write H_COLOR
but you can't even be sure there will be a .h in the name! Actually, I
like the symmetry, now that I see it, and I may use this myself.

<snip>
--
Ben.

Emanuel Berg

unread,
Apr 11, 2018, 6:07:51 PM4/11/18
to
Ben Bacarisse wrote:

>> So for color.c, color.h should have
>> H_COLOR_H?
>
> That is safe, yes. Doing it by hand, I think
> most people write H_COLOR but you can't even
> be sure there will be a .h in the name!

(defun insert-header-preprocessor-definition ()
(interactive)
(let*((filename (buffer-name))
(label (upcase (replace-regexp-in-string "\\." "_" filename)))
(safe-label (concat "H_" label))
(beg-string (concat
"#ifndef " safe-label "\n"
"#define " safe-label "\n\n"))
(end-string "\n#endif") )
(save-excursion
(goto-char (point-min))
(insert beg-string)

(goto-char (point-max))
(beginning-of-line)
(insert end-string) )
))
(defalias 'hep #'insert-header-preprocessor-definition)

http://user.it.uu.se/~embe8573/emacs-init/ide/c-and-cpp.el

Emanuel Berg

unread,
Apr 14, 2018, 7:54:53 PM4/14/18
to
Ben Bacarisse wrote:

> That is safe, yes. Doing it by hand, I think
> most people write H_COLOR [...] Actually,
> I like the symmetry

I like symmetry too but not for symmetry's
sake, so I removed the part that transformed
".h" into "_H" - which, ironically, I didn't
put there for the symmetry! Anyway now it is
just H_COLOR. [1]

Also, altho I've thought about this on and off
since I heard of it, I have failed to come to
terms with the underlying issue. How can
COLOR_H lead to an error when H_COLOR (or
H_COLOR_H) doesn't?

Because the syntax is the same, and all letters
are plain ASCII (the 2^7 table, where "_", the
underscore or "unit separator", is at number 95
counting from 0; see ascii(7)).

So there must be some fishy semantics going on.
Perhaps one needs to do a special study of the
C preprocessor? And if so, are there other
conventions one should be aware of?

And just what kind of error is it we're
trying (succeeding) to avoid?

[1] http://user.it.uu.se/~embe8573/emacs-init/ide/c-and-cpp.el

Ben Bacarisse

unread,
Apr 14, 2018, 9:03:03 PM4/14/18
to
Emanuel Berg <moa...@zoho.com> writes:

> Ben Bacarisse wrote:
>
>> That is safe, yes. Doing it by hand, I think
>> most people write H_COLOR [...] Actually,
>> I like the symmetry
>
> I like symmetry too but not for symmetry's
> sake, so I removed the part that transformed
> ".h" into "_H" - which, ironically, I didn't
> put there for the symmetry! Anyway now it is
> just H_COLOR. [1]
>
> Also, altho I've thought about this on and off
> since I heard of it, I have failed to come to
> terms with the underlying issue. How can
> COLOR_H lead to an error when H_COLOR (or
> H_COLOR_H) doesn't?

Yes, COLOR_H is almost certainly safe too. The issue is to find a
general rule that works regardless of the file name.

The C standard lists, for every header, any patterns of macro names that
are reserved to the implementation. errno.h, for example, reserves all
macro names that start E followed by a digit or another upper case
latter. Thus a program that uses ERROR_H whilst also including errno.h
is technically undefined even if errno.h does not actually use that
macro name.

None of the headers reserve any names that start H_ so that pattern
happens to be safe. There are lots of other ways to start the macro
name that will also be safe, but H_ has a certain appeal and is popular
with people who worry about the letter of the law.

<anip>
--
Ben.

Yuri Khan

unread,
Apr 15, 2018, 3:45:15 AM4/15/18
to Ben Bacarisse, help-gnu-emacs
On Sun, Apr 15, 2018 at 8:02 AM, Ben Bacarisse <ben.u...@bsb.me.uk> wrote:

> The C standard lists, for every header, any patterns of macro names that
> are reserved to the implementation. errno.h, for example, reserves all
> macro names that start E followed by a digit or another upper case
> latter. Thus a program that uses ERROR_H whilst also including errno.h
> is technically undefined even if errno.h does not actually use that
> macro name.

The issue is not limited to standard headers. As long as you start
using libraries, you are going to include their headers. Woe unto you
if you clash with any macros they define, or with any of their header
include guards, past, current or future.

The practical solution is, of course, the same as with all name
conflict issues: Namespacing. That is, in your project, you start all
preprocessor defines with the name of your project. And if the project
name is not unique enough, then also with your own name or the name of
your company.

On the other hand, the two or three compilers out there
that are most likely to be used to compile your project
already support #pragma once.

Emanuel Berg

unread,
Apr 15, 2018, 3:35:47 PM4/15/18
to
Ben Bacarisse wrote:

> The C standard lists, for every header, any
> patterns of macro names that are reserved to
> the implementation. errno.h, for example,
> reserves all macro names that start
> E followed by a digit or another upper case
> latter. Thus a program that uses ERROR_H
> whilst also including errno.h is technically
> undefined even if errno.h does not actually
> use that macro name.
>
> None of the headers reserve any names that
> start H_

Right, but what about stuff that aren't part of
the C standard library?

Emanuel Berg

unread,
Apr 15, 2018, 3:46:59 PM4/15/18
to
Yuri Khan wrote:

> The practical solution is, of course, the
> same as with all name conflict issues:
> Namespacing. That is, in your project, you
> start all preprocessor defines with the name
> of your project.

Woah, is *that* what people mean with
"namespacing"? I thought that was something
more advanced!

I remember people using it in C++ and I removed
it telling everyone it was a bad idea and
instead one should use the whole path to
identify things.

Looking back y'all, I don't know if that was
the right thing to say/do, but what I remember
everyone did it and in the end the software
worked :)

But that was not namespacing in this sense,
which is rather a naming convention, like
a poor-man's Hungarian notation or actually
what we do in Elisp all the time!

Maybe the supposedly "advanced" C++ way is
actually nothing more than syntax to automate
this and make people confused at the same time?

> On the other hand, the two or three compilers
> out there that are most likely to be used to
> compile your project already support
> #pragma once.

I'm on gcc 4.9. Should I get away with the
guards and use '#pragma once' instead?

Ben Bacarisse

unread,
Apr 15, 2018, 5:10:26 PM4/15/18
to
Emanuel Berg <moa...@zoho.com> writes:

> Ben Bacarisse wrote:
>
>> The C standard lists, for every header, any
>> patterns of macro names that are reserved to
>> the implementation. errno.h, for example,
>> reserves all macro names that start
>> E followed by a digit or another upper case
>> latter. Thus a program that uses ERROR_H
>> whilst also including errno.h is technically
>> undefined even if errno.h does not actually
>> use that macro name.
>>
>> None of the headers reserve any names that
>> start H_
>
> Right, but what about stuff that aren't part of
> the C standard library?

I'm not sure what to say about that. That's a well-known problem with
no ideal solution. And what might be a suitable non-ideal solution
will, most likely, vary from project to project.

But if more and more people use H_ to start guards, that will become a
de-facto standard and will discourage the use of H_ names for other
uses.

Alternatively, you could use a standard-C safe prefix that is very
unlikely to be used by anything else:

#ifdef Emanuel_Berg_EMACS_GENERATED_GUARD_FOR_COLOR_H

(Em... is not reserved by errno.h)

--
Ben.

Emanuel Berg

unread,
Apr 15, 2018, 5:45:03 PM4/15/18
to
Ben Bacarisse wrote:

> #ifdef Emanuel_Berg_EMACS_GENERATED_GUARD_FOR_COLOR_H
>
> (Em... is not reserved by errno.h)

Ha ha :)

OK, this is what Mr. Khan said as well.

Yuri Khan

unread,
Apr 16, 2018, 1:36:03 AM4/16/18
to Emanuel Berg, help-gnu-emacs
On Mon, Apr 16, 2018 at 2:46 AM, Emanuel Berg <moa...@zoho.com> wrote:
>> The practical solution is, of course, the
>> same as with all name conflict issues:
>> Namespacing. That is, in your project, you
>> start all preprocessor defines with the name
>> of your project.
>
> Woah, is *that* what people mean with
> "namespacing"? I thought that was something
> more advanced!

Well, yes, I define namespacing as the means to subdivide a _space_ of
_names_ into subspaces so that names from different subspaces are
guaranteed to not clash. Each such subspace is a _namespace_.

Many languages and environments have first-class support for
namespaces. For example, in the UNIX file system, a directory is a
namespace. In C++, a fully qualified name starts with ::, followed by
namespace names separated by ::, followed by an identifier.

> I remember people using it in C++ and I removed
> it telling everyone it was a bad idea and
> instead one should use the whole path to
> identify things.

Some languages let programmers access all names in a namespace as if
they were local. In C++, “using namespace foo;”; in Python, “from foo
import *”; etc. By many coding standards and conventions, these are
discouraged, because they make it harder to reason about the complete
set of names accessible at a point, and where each name comes from.

In small scopes, wholesale importing a namespace is okay, and
sometimes even necessary.

>> On the other hand, the two or three compilers
>> out there that are most likely to be used to
>> compile your project already support
>> #pragma once.
>
> I'm on gcc 4.9. Should I get away with the
> guards and use '#pragma once' instead?

https://en.wikipedia.org/wiki/Pragma_once#Portability says GCC has
supported #pragma once since 3.4.

Of course, when you work in a team, such decisions are best taken collectively.

Emanuel Berg

unread,
Apr 16, 2018, 2:16:40 AM4/16/18
to
Yuri Khan wrote:

> Of course, when you work in a team, such
> decisions are best taken collectively.

Often in life, it is easier to get a permission
to do something if you ask for it *after* you
do it! Anyway thanks for the info. I'll get
away with the guards. The only bummer is now
what will I do with that Elisp?
The cylindro-archive...
0 new messages