1) Насчет типов - вы 100% правы. Стандартные типы навроде int - могут зависеть от разрядностии процессора. Указатели - и подавно. Это документированная особенность. На х86 int вообще 32 бита бывает. Если на такие вещи не закладываться а писать код нормально, делать как советует Lampus, проблем не будет. Математика вообще без проблем с восьминогой тиньки на какой-нибудь ксеон перенесется.
2) Разумеется, специфика и компилера и платформы - зло. Если так выщло что оно неизбежное (например, низкоуровневая работа с периферией, специфичная для конкретного чипа и только него) - это логично вынести в отдельную четко очерченную сущность, с платформонезависимым интерфейсом для остального кода наружу. Чтобы потом иметь возможность без особого геморроя перейти на другую платформу/чип/что там еще. Отсюда же следует что не стоит увлекаться уникальными фичами конкретного чипа которых нет у остальных. Чтобы потом не было мучительно больно, если чип снимут с производства, а у остальных не окажется аналогов нужной фичи.
3) Вообще, по возможности не стоит не закладываться на endianess. Если данными надо меняться с внешним миром и при том в предсказуемом формате, который будут разгребать другие, лучше всего сделать универсальные врапперы, выдающие всегда правильные и предсказуемые форматы. Неплохой пример как это делать можно найти где-то в районе
http://www.oberhumer.com/opensource/ucl/ - довольно портабельная либа сжатия данных, которая работает под массой платформ. С напрочь разными endianess, размерами указателей, integer'ов и что там еще. Потенциально можно немного проиграть в скорости, хотя современные компиляторы обычно допирают довольно хорошо заоптимизировать такие вещи.
4) +100500. Оно не обязано называться именно HAL, но суть именно та самая :)