Introduction

This document is a collection of some of the interesting constructs that are possible in C and C++. While "nice" these features may not serve to increase code clarity but to obfuscate it. Your mileage may vary.



Playing with the C stack

Parameters on the stack appear in memory with the leftmost item at the lowest memory location. Thus you can get a pointer to your functions stack frame, and walk the parameter list, or even cast your stackframe to a struct that can be passed to other functions.

The first sample demonstrates how to retrieve the pointer to any variable parameters passed to the function.

int __cdecl printf(char const* pszFmt,...)
{
  char buf[1024];
  return wvsprintf(buf,pszFmt,&pszFmt+1);
}

This sample demonstrates how the functions passed to a function can be passed to another function.

BOOL InvalidateRect(
  HWND hwnd,
  LONG left,
  LONG top,
  LONG right,
  LONG bottom,
  BOOL fErase)
{
  return InvalidateRect(hwnd,(LPRECT)&left,fErase);
}


Constructing variable length structs

A trick to using structs that have a variable sized member is to use an overloaded operator new to allocate space for the struct.

struct string {
  int cb; // a data member
  char sz[]; // the string data

  void* operator new(int cb, int cbExtra){
    return new char[cb+cbExtra];
  }
};

Now contrast the following code to create such a struct:

  ...
  string* pStr = new(strlen(pszInString)) string;
  ...

The "C" method of working with variable sized looks like this

  ...
  string* = (string*)new char[sizeof(string) + strlen(pszInString)];
  ...


Working with big endian data

A have always favored little endian number representation over big-endian, which why I was saddened whn I found that TCP/IP, and most internet protocols (such as SSL3) use a big endian representation for numbers. Following is the type of construct I use when I need to work with a non-native data type in structs that I pull off of the network.


typedef unsigned char uint8;

struct uint16 {
  uint8 n[2];

  operator unsigned short(){
    return ((unsigned short)n[0] << 8) + n[1];
  }
};

Using a struct like this has two advantages:

  1. If a typedef unsigned short was used you could accidently use the number in situations without converting it.
  2. The operator unsigned short ensures that the struct can be used as a normal unsigned short where required