Какова была первоначальная причина использовать последовательность триграфа некоторых символов, чтобы стать другими символами в ANSI C, например:
??=define arraycheck(a, b) a??(b??) ??!??! b??(a??)
становится
#define arraycheck(a, b) a[b] || b[a]
Краткий ответ: клавиатуры / кодировки символов, которые не включают такие графики.
Из википедии:
Базовый набор символов языка программирования C является надмножествомНабор символов ASCII, который включает в себя девять символов, которые находятся за пределами набора символов инварианта ISO 646.Это может создать проблему при написании исходного кода, когда используемая клавиатура не поддерживает ни один из этих девяти символов.Комитет ANSI C изобрел триграфы как способ ввода исходного кода с помощью клавиатур, поддерживающих любую версию набора символов ISO 646.
http://en.wikipedia.org/wiki/Digraphs_and_trigraphs
На некоторых старых клавиатурах не было специальных символов, поэтому язык обходился без них, позволяя вместо этого использовать триграфы.