here is the question, what does str(X) become

#define str_(X) #X
#define str(X) str_(X)

when X is a string? is it ""string"" or "\"string\""?

Well just giving it a try shows that it becomes "X", with quotes.

When you write ""string"", it doesn't make sense syntax wise because the first double-quote gets matched with the next double quote, and so on. Hence ""string"", gets interpreted as a empty string, followed by the identifier with name string, followed by another empty string. In your second example, you tell the interpreted to use the double-quote as a literal character and not a special character, hence "\"string\"", gets interpreted as a string which contains a double-quote followed by the characters in string, then followed by a literal double-quote.