2016-12-28 2 views
-1

Actuellement pour un fichier d'en-tête nommé test_header.h J'utilise -Existe-t-il un moyen d'implémenter une garde d'en-tête qui n'a pas besoin d'être modifiée lorsque le fichier d'en-tête est renommé?

#ifndef TEST_HEADER_H 
#define TEST_HEADER_H 
/* code */ 
#endif /* TEST_HEADER_H */ 

Ce que je veux est un garde d'en-tête qui n'utilise pas directement le nom du fichier. Quelque chose comme (dire hypothétique solution brute wishful) -

#if __FILE__ not in INCLUDE_LIST 
#APPEND(INCLUDE_LIST, __FILE__) 
/* code */ 
#endif 
+3

Strictement parlant, vous n'avez pas besoin de changer de garde-tête après le changement de nom - à moins que vous n'ayez un autre fichier qui reprend l'ancien nom. – Arkadiy

+0

Je sais, mais de cette façon je peux être sans souci (sic). –

+2

Vous pouvez utiliser un identifiant avec un préfixe plus un UUID et être encore plus sans souci. –

Répondre

2

Comme d'autres l'ont noté, ce que vous utilisez comme une garde d'en-tête n'est pas intrinsèquement important; il doit juste être unique dans l'ensemble des en-têtes qui pourraient être inclus.

Vous pouvez créer un UUID ou un GUID et l'utiliser comme garde d'en-tête (ou un hachage quelconque - MD5, SHA1, SHA2, SHA3, ...). Le seul truc consiste à traiter la possibilité d'un chiffre principal; cela est facile à contourner (j'ai utilisé H_ comme préfixe). Mais généralement, j'utilise un nom basé sur le nom du fichier, et ne renomme pas assez souvent les en-têtes, ce qui est un problème.

Voici un script appelé hdrguard que j'utilise pour générer les lignes de garde d'en-tête d'un fichier d'en-tête donné:

#!/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 "[email protected]" 
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 

Il n'a pas de code pour SHA1, SHA2 ou SHA-3 - il utilise en option MD5 (en la forme d'une commande md5). Il ne serait pas très difficile d'ajouter du support pour des algorithmes de hachage alternatifs. Il ne nécessite pas l'existence du fichier.

Exemple utilise:

$ 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 */ 

$ 

J'utilise souvent de l'intérieur vim, en tapant une commande telle que !!hdrguard % lorsque le curseur est sur une ligne vide pour générer un garde d'en-tête approprié pour l'en-tête, je suis édition. C'est pourquoi il génère aussi les lignes vides en haut et en bas. La commande utilise les scripts isodate et rcsmunger.Avec l'argument compact, la commande isodate équivaut à:

date +'%Y%m%d.%H%M%S' 

La commande complète prend en charge un certain nombre de formats alternatifs et est plus succinct que d'avoir à taper la commande date partout. Vous êtes entièrement libre de renoncer à l'utilisation d'un script séparé et de simplement intégrer l'extension affichée dans hdrguard. En effet, vous pourriez utiliser seulement date et ce serait OK; c'est juste le matériel de graine pour l'opération de hachage pour rendre les données étant hashed uniques.

$ isodate compact 
20161228.185232 
$ 

La commande rcsmunger convertit simplement les chaînes d'identification RCS dans un format que je préfère pour signaler les informations de version:

#!/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; 

Par exemple:

$ hdrguard -V 
hdrguard: HDRGUARD Version 1.8 (2016-05-09 18:41:57) 
$ 

Vous pouvez considérer l'impression des informations sur la version comme contrôle de version old-school; il doit être fait différemment si vous utilisez un DVCS tel que git, qui est l'une des raisons pour lesquelles je n'ai pas fait une migration en gros à git pour ma collection de logiciels personnels.

4

Vous pouvez nommer les gardes d'en-tête tout ce que vous aimez.

  • Si votre tête est liée à un certain sujet, nommez après que LIST_OPERATIONS à savoir
  • Omettre les gardes et écrire un script qui les insère en fonction du nom du fichier en cours. Exécutez ce script dans le cadre de votre processus de compilation avant de compiler. (N'oubliez pas de créer une copie modifiée ou de supprimer les inclusions après la construction, sinon vous vous retrouverez avec beaucoup de gardes d'inclusion dans votre en-tête)
  • Selon les compilateurs qui devraient être utilisés pour votre projet, ils pourraient supporter les #pragma once approche.
+0

Votre script peut également supprimer les anciens gardes d'include s'ils ont un format distinctif, ou ne rien faire si les bons gardes sont déjà présents – Arkadiy

3

#pragma once

Il est très portable, être bien pris en charge par tous les principaux compilateurs et de 13 des 14 compilateurs (according to Wikipedia).

Consultez également #pragma once vs include guards?.

+1

Mais les programmes qui utilisent '#pragma once' ne sont pas conformes. Si votre objectif est d'écrire du code portable, vous ne l'utiliserez pas, malgré la proportion de compilateurs majeurs qui le soutiennent. –