Inferred magic numbers

Putting “magic” numbers in source code is supposedly bad.. for example..


  char myBuffer[12];
  for (int i=0; i<12; i++)
    myBuffer[i] = something;


Mainly they're bad because as code evolves, it's possible that something will come between the declaration of myBuffer and the loop that's using it.. and perhaps someone will add more code that uses the same magic number:


  char myBuffer[12];


  // some other code

  for (int i=0; i<12; i++)
    myBuffer[i] = something;


  // more code

  char newBuffer[12];
  memcpy(newBuffer, myBuffer, 12);


This is fragile, because it's easy for someone to miss changing 12 in one spot when they need to change the number to something else later on.  For example, a very common sort of bug would be to change all the 12's except the one in the memcpy line at the end.. leading to hard to find bugs.


The usual solution is to say “never use magic numbers in code”.  This would turn into:


  // somewhere in a header..
  #define BUFFER_LENGTH 12


  // And in the source file..
  char myBuffer[BUFFER_LENGTH];


  // some other code

  for (int i=0; i<BUFFER_LENGTH; i++)
    myBuffer[i] = something;


  // more code

  char newBuffer[BUFFER_LENGTH];
  memcpy(newBuffer, myBuffer, BUFFER_LENGTH);


You might think “but you wouldn't call it BUFFER_LENGTH, that doesn't describe what the number is used for”.  Yeah no kidding.  But that's what people do.  (A Google search for “#define BUFFER_LENGTH” shows over 500 hits, strangely enough).


Thing is, BUFFER_LENGTH is redundant.  The “this buffer is so many bytes long” definition should be determined by looking at the actual size of the buffer:


  // And in the source file..
  char myBuffer[12];


  // some other code

  for (int i=0; i<sizeof(myBuffer); i++)
    myBuffer[i] = something;


  // more code

  char newBuffer[sizeof(myBuffer)];
  memcpy(newBuffer, myBuffer, sizeof(newBuffer));


It's obviously from the declaration of myBuffer that it's a 12 byte buffer, and it's no less descriptive than the version with the silly #define.  And it doesn't pollute the namespace.  I mean, what's a generic defined name like BUFFER_LENGTH doing outside a very local scope in any code?


In C++, you have the problem that if you need to pass myBuffer to another function in another module, and you want that module to be able to assume it's size (instead of passing it, which is probably better), then you need a global define.  This is fine, but give it a meaningful name.


In C#, myBuffer.Count will tell you how big it is. 


Oh, and don't call your buffer “myBuffer”.  :)