Is saying a cache is a special kind of buffer correct? They both perform similar functions, but is there some underlying difference that I am missing?
From Wikipedia's article on data buffers:
A buffer ends up cycling through and holding every single piece of data that is transmitted from one storage location to another (like when using a circular buffer in audio processing). A buffer allows just that - a "buffer" of data before and after your current position in the data stream.
Indeed, there are some common aspects of a buffer and a cache. However, cache in the conventional sense usually does not store all of the data when it's being moved from place to place (i.e. CPU cache).
The purpose of a cache is to store data in a transparent way, such that just enough data is cached so that the remaining data can be transferred without any performance penalty. In this context, the cache only "pre-fetches" a small amount of data (depending on the transfer rates, cache sizes, etc...).
The main difference is that a buffer will eventually have held all of the data. Conversely, a cache may have held all, some, or none of the data (depending on the design). However, a cache is accessed as if you were directly accessing the data in the first place - what exactly gets cached is transparent to the "user" of the cache.
The difference is in the interface. When you're using a cache to access a data source, you use it as if the cache is the data source - you can access every part of the data source through the cache, and the cache will determine where the data comes from (the cache itself, or the source). The cache itself determines what parts of the data get cached (usually the beginning, but sometimes all, some, or none). The best example of this is a system prefetcher/readahead, both of which load the parts of data they think you will use most into memory, and revert to the hard drive if something isn't cached.
Conversely, a buffer can't be used to instantaneously move your location in the data stream, unless the new part has already been moved to the buffer. To do so would require the buffer to relocate (given the new location exceeds the buffer length), effectively requiring you to "restart" the buffer from a new location. The best example of this is moving the slider in a Youtube video.
Another good example of a buffer is playing audio back in Winamp. Since audio files need to be decoded by the CPU, it takes some time between when the song is read in, to when the audio is processed, to when it's sent to your sound card. Winamp will buffer some of the audio data, so that there is enough audio data already processed to avoid any "lock-ups" (i.e. the CPU is always preparing the audio you'll hear in a few hundred milliseconds, it's never real-time; what you hear comes from the buffer, which is what the CPU prepared in the past).
It would be more accurate to say that a cache is a particular usage pattern of a buffer, that implies multiple uses of the same data. Most uses of "buffer" imply that the data will be drained or discarded after a single use (although this isn't necessarily the case), whereas "cache" implies that the data will be reused multiple times. Caching also often implies that the data is stored as it is also being simultaneously used, although this isn't necessarily the case (as in pre-fetching and the like), whereas buffering implies that the data is being stored up for later use.
There is certainly a large overlap in both implementation and usage, however.