I don't think there are any compilers that do this, and I suspect that there is no way to hack it in. You can't create new buffers to store strings in without engine extensions, and there's no way to access the individual elements of a string from QC. A string in QC is really just the pointer to where the array of characters is stored. These arrays are either loaded with the progs, loaded from the map data, or accessed from the 16 char array allocated for each player's name. The last one is about as dynamic as strings get in quake.
What could be hacked into a compiler is some kind of keyword/macro thing called _tokenize(string n) or something, which would do all the work of calculating the corresponding character index for each character in the string you feed it, and then send each byte as MSG_ALL or MSG_ONE. It would still only be useful for fixed strings liked "killed " above, not loaded frlom map data. But it would keep the code looking shorter and neater.
A slight step in that direction would be for each fixed string in the progs, create an array of floats, so killed would become
s_finale_killed[7] = {107,105,108,108,101,100,12}
Then you'd have a loop
while(i<7)
{
WriteByte(MSG_ALL,s_finale_killed[i])
i = i + 1;
}
which writes it, which looks a bit better than a row of 7 WriteByte statements, and is certainly nicer for longer strings.
Additional: The idea of sending strings byte by byte is done to a huge extent in Pyrdon Gate, which is where I first heard of the idea. The source to v1.5 of this mod can be found here:
http://mindart.quakedev.com/code_crazy.zip
Look at menu/print.qc for a good idea of how it's all done there. One of the most valuable tricks you'll see is once you have a function
p4(float a,b,c,d)
which sends those four floats as bytes over the current channel, you can do stuff like
p4('D', 'a', 'm', ':');
which converts the characters to numbers for you, in this case printing "Dam:". This might be a frikqcc only trick, but it's worth a look.