Moim prywatnym zdaniem ... jeśli to niczemu nie przeszkadza ... wszystkie zmienne bym zrobił "unsigned long long", i wszystkie stałe też (przyrostek "ULL") ...
unsigned long long int FTW, fs, frequency;
fs=400000000ULL; // "ULL" -> "unsigned long long"
// ...
// poniżej ... przyrostek "ULL" w stałej wymusi przeprowadzenie
// obliczeń w precyzji "unsigned long long", nawet jeśli "frequency"
// i/lub "fs" będą tylko "unsigned long"
FTW = 4294967296ULL * frequency / fs;
Poza tym, żeby być pewnym kolejności wykonywania działań ... dodałbym nawiasy ...
albo ...
FTW = (4294967296ULL * frequency) / fs;
albo ...
FTW = 4294967296ULL * (frequency / fs);
zależnie od tego jak bym chciał żeby się to liczyło.
A propos, kompilator nie ma żadnego prawa zmienić typu ani rozmiaru zmiennej ... może co najwyżej wyemitować ostrzeżenie (warning) jeśli uzna że coś może być nie tak (ale być może jest o.k. bo tego właśnie chciał użytkownik), a w przypadku bardziej krytycznych problemów zgłosić błąd (error) i przerwać działanie ... zawsze to użytkownik musi sam poprawić swój kod źródłowy.
Na koniec jeszcze jedna uwaga ... upewnij się że twój kompilator naprawdę traktuje typ "long long" jako 8B (a "long" jako 4B). Co więcej, jego zachowanie może zależeć od konkretnych flag (opcji kompilatora) podanych w trakcie kompilacji kodu źródłowego.
Standard mówi jedynie że (zwróć uwagę na znak "mniejsze-równe"):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
Naprościej byłoby po prostu napisać kawałek testujący:
printf("%d %d %d %d\n", sizeof(short), sizeof(int), sizeof(long), sizeof(long long));
printf("%d %d %d %d\n", sizeof(unsigned short), sizeof(unsigned int), sizeof(unsigned long), sizeof(unsigned long long));
Generalnie jednak, użyłbym typów "Uint64_t" albo "u64" - to gwarantuje "unsigned 8-Bytes" (i "Uint32_t" albo "u32" dla zmiennych "unsigned 4-Bytes" oraz "Uint8_t" albo "u08" dla zmiennych "unsigned 1-Byte").
https://ccrma.stanford.edu/courses/250a/...yntax.html
https://ccrma.stanford.edu/wiki/AVR_Programming