As others have noted, what you use as a header guard isn't intrinsically important; it just needs to be unique across the set of headers that might ever be co-included.
You can create a UUID or GUID and use that as the header guard (or a hash of some sort — MD5, SHA1, SHA2, SHA3, …). The only trick is dealing with the possibility of a leading digit; that's easily worked around (I used H_
as a prefix).
Mostly though, I use a name based on the file name, and don't usually rename headers often enough that it is a problem.
Here's a script called hdrguard
that I use for generating the header guard lines for a given header file:
#!/bin/sh
#
# @(#)$Id: hdrguard.sh,v 1.8 2016/05/09 18:41:57 jleffler Exp $
#
# Generate #ifndef sequence to guard header against multiple inclusion
arg0=$(basename $0 .sh)
usestr="Usage: $arg0 [-bdfhimV] header.h [...]"
usage()
{
echo "$usestr" 1>&2
exit 1
}
help()
{
echo "$usestr"
echo
echo " -b Use base name of file for guard"
echo " -d Use _DOT_H after name (instead of _H)"
echo " -f Use specified path name of file for guard (default)"
echo " -h Print this help message and exit"
echo " -i Omit _INCLUDED after name"
echo " -m Generate MD5 hash value as header guard"
echo " -V Print version information and exit"
exit 0
}
opt_incl=yes
opt_base=no
opt_dot=no
opt_md5=no
while getopts bdfhimV opt
do
case "$opt" in
(b) opt_base=yes;;
(d) opt_dot=yes;;
(f) opt_base=no;;
(h) help;;
(i) opt_incl=no;;
(m) opt_md5=yes;;
(V) echo "$arg0: HDRGUARD Version "'$Revision: 1.8 $ ($Date: 2016/05/09 18:41:57 $)' | rcsmunger; exit 0;;
(*) usage;;
esac
done
shift $(($OPTIND - 1))
[ $# -eq 0 ] && usage
for i in "$@"
do
if [ $opt_base = yes ]
then i=$(basename $i)
fi
if [ $opt_dot = yes ]
then i=$(echo "$i" | sed 's/\.h$/_dot_h/')
fi
i=$(echo $i | tr 'a-z' 'A-Z' | tr -s '/+.-' '____' | sed 's/^_//')
if [ $opt_incl = yes ]
then
case "$i" in
(*_INCLUDED)
: OK;;
(*)
i="${i}_INCLUDED";;
esac
fi
if [ $opt_md5 = yes ]
then
tmp=$(mktemp ./hdrgrd.XXXXXXXX)
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
echo "$i.$(isodate compact)" > "$tmp"
i=$(md5 "$tmp" | sed 'y/abcdef/ABCDEF/; s/\([^ ]*\) .*/H_\1/')
rm -f "$tmp"
trap 0 1 2 3 13 15
fi
echo
echo "#ifndef $i"
echo "#define $i"
echo
echo "#endif /* $i */"
echo
done
It doesn't have code for SHA1, SHA2 or SHA3 — it optionally uses MD5 (in the form of a command md5
). It would not be very hard to add support for alternative hashing algorithms. It doesn't require the file to exist.
Example uses:
$ hdrguard header.h
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
#endif /* HEADER_H_INCLUDED */
$ hdrguard -m header.h
#ifndef H_6DC5070597F88701EB6D2CCAACC73383
#define H_6DC5070597F88701EB6D2CCAACC73383
#endif /* H_6DC5070597F88701EB6D2CCAACC73383 */
$
I frequently use it from within vim
, typing a command such as !!hdrguard %
while the cursor is on an empty line to generate a header guard suitable for the header I'm editing. That's why it generates the blank lines top and bottom, too.
The command uses scripts isodate
and rcsmunger
. With the argument compact
, the isodate
command is equivalent to:
date +'%Y%m%d.%H%M%S'
The complete command supports a number of alternative formats and is more succinct than having to type the date
command out everywhere. You're entirely at liberty to forego the use of a separate script and to just embed the expansion shown into hdrguard
. Indeed, you could use just date
and it would be OK; it is just seed material for the hashing operation to make the data being hashed unique.
$ isodate compact
20161228.185232
$
The rcsmunger
command just converts RCS ID strings into a format I prefer for reporting version information:
#!/usr/bin/env perl -p
#
# @(#)$Id: rcsmunger.pl,v 1.9 2015/11/02 23:54:32 jleffler Exp $
#
# Remove the keywords around the values of RCS keywords
use strict;
use warnings;
# Beware of RCS hacking at RCS keywords!
# Convert date field to ISO 8601 (ISO 9075) notation
s%\$(Date:) (\d\d\d\d)/(\d\d)/(\d\d) (\d\d:\d\d:\d\d) \$%\$$1 $2-$3-$4 $5 \$%go;
# Remove keywords
s/\$([A-Z][a-z]+|RCSfile): ([^\$]+) \$/$2/go;
For example:
$ hdrguard -V
hdrguard: HDRGUARD Version 1.8 (2016-05-09 18:41:57)
$
You can regard the printing of version information as old-school version control; it has to be done differently if you use a DVCS such as git
, which is one reason I've not done a wholesale migration to git
for my personal software collection.