Strings are basically atoms that don't go into the atom table. There is a little advantage of having strings, since the atom table is mainly used to invoke predicates and but not very useful when you have many distincts atoms.
The need for strings has recently been a little bit mitigated, since some Prolog systems also feature atom table garbage collection. Some Prolog systems even don't have an atom table at all.
Here is a simple test case to see performance of atoms, that they often can be used instead of strings if either atom table garbage collection is present or if the Prolog system doesn't have an atom table.
SWI-Prolog atoms, some atom table GC:
?- time(test).
% 8,209,791 inferences, 1.125 CPU in 1.140 seconds (99% CPU, 7297592 Lips)
false.
SWI-Prolog strings:
?- time(test2).
% 8,209,791 inferences, 0.750 CPU in 0.749 seconds (100% CPU, 10946388 Lips)
false.
Jekejeke Prolog atoms, no atom table:
?- time(test).
% Up 1,398 ms, GC 14 ms, Thread Cpu 1,360 ms (Current 08/18/18 20:35:56)
No
So I guess there is some impact of strings. Maybe a better solution than SWI-Prolog strings would be atoms that can automatically also serve as strings on demand, like in Jekejeke Prolog. This would much less blow up the number of built-ins.
P.S.: I used the following test code:
test :-
between(1,127,A), between(1,127,B), between(1,127,C),
atom_codes(X,[A,B,C]), atom_codes(X, L), L\==[A,B,C].
test2 :-
between(1,127,A), between(1,127,B), between(1,127,C),
string_codes(X,[A,B,C]), string_codes(X, L), L\==[A,B,C].