Vim Header Guard Trick

Note: This entry has been restored from old archives.

Quite some time ago a friend of mine at work supplied us with a magical vim binding that generated safe header guards. (And copyright/licence/doxygen preamble too!) The idea is that it automatically inserts the matching (#ifndef, #define, #endif) triplet and uses a guard that incorporates the file name and a suitably long random number. (The random number is what makes it “safe”, for example what if you have a “UTIL_H” but another library you’re using also has a “UTIL_H“?)

Today I went to use the trusty old insert-guard key-binding and I see: “shell returned 127“. The problem was a simple one, the vim binding called on a script written by yet another colleague. I had copied my usual .vimrc over but not the required script so the guard failed. Since I’m easily distracted I decided to work out a way to generate the guards that wouldn’t do this to me again, rather than just scp the script onto the system! I ended up with this:

" function to insert a C/C++ header file guard
function! s:InsertGuard()
  let randlen = 7
  let randnum = system("xxd -c " . randlen * 2 . " -l " . randlen . " -p /dev/urandom")
  let randnum = strpart(randnum, 0, randlen * 2)
  let fname = expand("%")
  let lastslash = strridx(fname, "/")
  if lastslash >= 0
    let fname = strpart(fname, lastslash+1)
  endif
  let fname = substitute(fname, "[^a-zA-Z0-9]", "_", "g")
  let randid = toupper(fname . "_" . randnum)
  exec 'norm O#ifndef ' . randid
  exec 'norm o#define ' . randid
  let origin = getpos('.')
  exec '$norm o#endif /* ' . randid . ' */'
  norm o
  -norm O
  call setpos('.', origin)
  norm w
endfunction

" keymap Ctrl-g to the InsertGuard function
map <silent> <C-g> :call <SID>InsertGuard()<CR>

It is still dependent on an external command, but if vim is installed then xxd is pretty likely to be around! (Since xxd is part of the vim toolset.) I wonder if it could be shorter? I didn’t find an obvious equivalent to “basename” in vim, I suspect there might be an alternative variable to ‘%‘ that gives what I want.

An example of what it generates when you’re editing “src/util.h” and hit Ctrl-h:

#ifndef UTIL_H_668A545328A5CC
#define UTIL_H_668A545328A5CC

<existing file content>

#endif /* UTIL_H_668A545328A5CC */

5 thoughts on “Vim Header Guard Trick”

  1. Or simply follow the guru footprints and…

    include files should never include include files.

  2. Yeah, I’m familiar with the mantra, in fact I’m pretty certain I first picked it up from you back when you taught good old “PP” at Uni! It is something I /do/ try to do, though at best it tends to turn into minimisation rather than prohibition. But it’s really all or nothing isn’t it, my mere /trying/ isn’t good enough! 🙂

    That said, if working on an library interface I aim to follow that rule 100%, so that victims of the API don’t suffer the very problem I worry about. The lack of discipline only applies to the internal code.

    It doesn’t solve the problem of your own .cc file including your own “util.h” and then including from some third party library that its self includes its own “util.h”. You just have to hope that everyone else reasonably “warts” their #ifndef guards as well.

    You know, now I’ve bothered to add comments I should add an opt-in “email me comments on this story” too. Anyway…

  3. It solves the problem of you own util.h and some library code’s util.h, since your util.h doesn’t hsve include guards in the first place. Of course that was from a simpler time when things didn’t have so many dependencies…

    Requiring code that uses x.h to do:

    #include “a.h”
    #include “b.h”
    #include “c.h”
    #include “x.h”

    was OK, when it was only ever 2 or 3 extra includes, but now that it tends to be dozens, it doesn’t work…

    Of course you still have the problem of two third party libs you are using both using the same include guard name. But so does your technique – unless everyone uses it…

    why there isn’t a “include this file if it hasn’t already been included” preprocessor command (in addition to #include obviously, sometimes you want to include something multiple times – poor man’s templates for example) in the standard I’ll never understand – it would be trivial to implement (a lookup table of files already included), faster (no need to parse the entire file everytime it is included to find the #endif), and the whole problem goes away. PHP has one for fuck sake…

    By the way a preview comment would be nicer than a “email the address I signed up with and never check since it’d a spam magnet” feature.

  4. Yeah, I guess “my technique” is just a matter of “everyone does it, don’t they?” … and those of us who do (most C/C++ monkeys I assume) just keep our fingers crossed.

    As for the last note. Better than an email “push” would be comment feed RSS “pull”… but email is easier to implement! Yes, comment preview would be good, I’ll bump it up to somewhere above “eat hippo” on my TODO list.

Comments are closed.