Robert Floyd invented a sampling algorithm for just such situations. It's generally superior to shuffling then grabbing the first x elements. As originally written it assumes values from 1..N, but it's trivial to produce 0..N, and/or use non-contiguous values by simply treating the values it produces as subscripts into a vector/array/whatever.
In pseuocode, the algorithm runs like this (stealing from Jon Bentley's Programming Pearls column "A sample of Brilliance").
initialize set S to empty
for J := N-M + 1 to N do
T := RandInt(1, J)
if T is not in S then
insert T in S
else
insert J in S
That last bit (inserting J if T is already in S) is the tricky part, but the bottom line is that it assures precisely the correct mathematical probability of inserting J, so it produces correct, unbiased results.