Para as instrulções if, while, do/while e for, a condição de parada (termo técnico muito utilizado) para linguagem c (não posso afirmar se para c++ é igual porque não conheço) é que tudo o que for diferente de zero é considerado true, zero é false, logo…
while (1) {
...
}
Em linguagens modernas seria o mesmo que…
while (true) {
...
}
Nesse caso que você mostrou, envolve uma atribuição vinda de um cálculo certo? O parênteses (precedência) força o cálculo ser realizado primeiro e logo ser atribuído a variável c, após isso o valor de c é que será testado pelo while seguindo o que lhe falei acima, se o c é 0 dá false e o while vai parar, caso o contrário é true e o while continua calculando e testando… clareou um pouco mais?
Até onde sei não precisa parenteses nem em C nem em C++.
No mais, complementando sua resposta:
Em C++ (e até onde sei também em C) o resultado de uma atribuição é o valor que foi atribuído à variável, por exemplo:
x = 1;
Acima, o valor resultante dessa expressão de atribuição é o valor que foi armazenado em x, no caso 1. Isto é usado em coisas como atribuições encadeadas:
int z, y, x;
z = y = x = 1;
O valor de z, y e x será 1. Isto se dá porque a expressão é avaliada de direita para a esquerda
z = (y = (x = 1));
atribuindo 1 a x, e o operador = irá retornar o valor que foi atribuído a x, no caso 1. Logo após este 1 é atribuído a y e o resultado dessa atribuição é passado ao próximo operador que vai atribuir o valor de y (também 1) a z.
Em relação a usar isso dentro de um loop, em C++ o valor de uma condição é convertido implicitamente a bool. No caso inteiro diferente de zero será considerado true.