Поскольку определения макросов развертываются в тексте до самой компиляции,
isupper(c = getchar())
расширится до
((c = getchar()) >= 'A' && (c = getchar()) <= 'Z')
, который по правилу короткого замыкания для &&
вызывает getchar
дважды, если он возвращает >= 'A'
в первый раз и присваивает c
значение, возвращаемое при втором вызове.