2016-12-28 2 views
-1

В настоящее время для заголовка файла с именем test_header.h я использую -Есть ли способ реализовать защиту заголовка, которая не нуждается в изменении при переименовании файла заголовка?

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

То, что я хочу, это охранник заголовок, который не использует имя файла напрямую. Нечто подобное (т.е. желаемого сырой гипотетического решения) -

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

Строго говоря, вы не _need_, чтобы изменить защиту заголовка после переименования - если только у вас нет другого файла, который использует старое имя. – Arkadiy

+0

Я знаю, но таким образом я могу быть беззаботным (sic). –

+2

Вы можете использовать идентификатор с префиксом плюс UUID и быть еще более беззаботным. –

ответ

2

Как уже отмечалось, то, что вы используете в качестве защитника заголовка, не имеет принципиального значения; он просто должен быть уникальным во множестве заголовков, которые могут быть включены одновременно.

Вы можете создать UUID или GUID и использовать его как защитник заголовка (или хэш какого-то типа - MD5, SHA1, SHA2, SHA3, ...). Единственный трюк имеет дело с возможностью вести цифру; это легко работает (я использовал H_ в качестве префикса).

В основном, однако, я использую имя на основе имени файла и обычно не переименовываю заголовки достаточно часто, чтобы это было проблемой.

Вот скрипт называется hdrguard, который я использую для генерации заголовка сторожевых линий для данного файла заголовка:

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

Он не имеет кода SHA1, УВХ2 или SHA-3 - это необязательно использует MD5 (в форма команды md5). Было бы не очень сложно добавить поддержку альтернативных алгоритмов хеширования. Он не требует, чтобы файл существовал.

Пример использования:

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

$ 

Я часто использую его изнутри vim, набрав команду, такие как !!hdrguard %, когда курсор находится на пустой строке, чтобы генерировать охранник заголовок, подходящий для заголовка я редактирования. Вот почему он также создает пустые строки сверху и снизу.

Команда использует сценарии isodate и rcsmunger.С аргументом compact команда isodate эквивалентна:

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

Полной команда поддерживает ряд альтернативных форматов и более емкие, чем того, чтобы набрать команду date везде. Вы полностью можете отказаться от использования отдельного сценария и просто вставить расширение, показанное на hdrguard. В самом деле, вы можете использовать только date, и все будет в порядке; это всего лишь материал семян для операции хеширования, чтобы сделать хеширование данных уникальным.

$ isodate compact 
20161228.185232 
$ 

Команда rcsmunger просто преобразует строки ID RCS в формат, я предпочитаю для представления информации о версии:

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

Например:

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

Вы можете рассматривать печать информации о версии как контроль версий старой школы; это нужно сделать по-другому, если вы используете DVCS, например git, что является одной из причин, по которым я не совершил оптовую миграцию до git для моей личной коллекции программного обеспечения.

4

Вы можете назвать охранников заголовка, что вы любите.

  • Если заголовок связан с определенной темой, назовите его после этого то есть LIST_OPERATIONS
  • опускает охранников и написать скрипт, который вставляет их на основе текущего имени файла. Запустите этот скрипт как часть процесса сборки перед компиляцией. (Не забудьте либо создать измененную копию, либо удалить включенные после сборки, в противном случае у вас будет множество защитных ограждений в вашем заголовке)
  • В зависимости от компиляторов, которые должны использоваться для вашего проекта, они могут поддерживать #pragma once подход.
+0

Ваш скрипт также может удалить старые включенные охранники, если они имеют отличительный формат, или ничего не делать, если правильные охранники уже присутствуют. – Arkadiy

3

#pragma once

Это очень портативный, будучи хорошо поддерживается всеми основными компиляторами, и 13 из 14 компиляторов (according to Wikipedia).

Также зарегистрируйтесь #pragma once vs include guards?.

+1

Но программы, которые используют '#pragma once', тем не менее, не являются строго соответствующими. Если ваша цель - написать переносимый код, вы не будете использовать его, несмотря на то, что большинство основных компиляторов поддерживают его. –

Смежные вопросы