Что-то не так с вашим исходным кодом, который вы нам не показали. Это потому, что следующее работает нормально:
#include <stdio.h>
static void fn (int a, uint64_t b, int c) {
uint64_t magicNum = 1;
if (magicNum == b)
puts ("They match!");
if ((uint64_t)magicNum == (uint64_t)b)
puts ("They still match!");
}
int main (void) {
fn (0xcd32ab00 ,1 ,2);
return 0;
}
Вывод:
They match!
They still match!
Исходя из вашего обновления, которое вы используете scanf("%d")
для получения значений, это довольно известная проблема для тех из нас, кто был извращен десятилетиями использования C: -)
Когда вы указываете %d
в качестве спецификатора формата, он ожидает указатель на тип int
и записывает в этот тип. Если указатель, указанный вами, имеет тип, который в два раза шире (скажем, 64 бита вместо 32), он будет записывать только в половину .
Вы можете увидеть это здесь:
int main (void) {
uint64_t x = 0xffffffffffffffffULL;
printf ("Enter your number: ");
scanf ("%d", &x); // signed int
printf ("%llu\n", x); // unsigned long long
return 0;
}
, который выводит -4294967295
при вводе 1
(потому что он не коснулся другой половины переменной, которая по-прежнему заполнена 1-битами).
Если вы измените строку формата scanf
на %llu
, она будет работать нормально.
Имейте в виду, что это только потому, что мои unsigned long long
значения имеют ширину 64 бита, как и мои unit64_t
. Для переносимости вы должны использовать макросы спецификатора формата, расположенные в inttypes.h
. Для uint64_t
правильным будет SCNu64
. Имена макросов формируются с помощью:
PRI
для строк формата printf
или SCN
для строк формата scanf
.
d
, i
, o
, u
, x
или X
для указания десятичного знака со знаком (d
и i
), восьмеричного знака без знака, десятичного знака без знака, нижнего регистра без знака шестнадцатеричный и беззнаковый верхний регистр шестнадцатеричный.
- необязательно
LEAST
, FAST
, MAX
или PTR
для различных типов переменных.
N
это размер бита.
SCNu64
расширяется до "llu"
в моей реализации, но это не всегда так везде. В системе с 64-битным int
и 256-битным long long
он, скорее всего, будет "u"
(поскольку он равен unsigned int
).
Пример кода, показывающего, как использовать эти строки формата, показан ниже:
#include <stdio.h>
#include <inttypes.h>
int main (void) {
uint64_t x = 0xffffffffffffffffULL;
printf ("Enter your number: ");
scanf ("%" SCNu64, &x);
printf ("%" PRIu64 "\n", x);
return 0;
}
Относительно того, почему ваш printf
может распечатать уменьшенное значение, см. Этот код:
#include <stdio.h>
#include <inttypes.h>
int main (void) {
uint64_t x = 0xffffffffffffffffULL;
printf ("Enter your number: ");
scanf ("%u", &x);
printf ("uint64_t = %" PRIu64 "\n", x);
printf ("uint64_t = %" PRIu64 " (when and'ed)\n", x & 0xffffffffU);
printf ("uint = %u\n", x);
return 0;
}
который выводит:
Enter your number: 5
uint64_t = 18446744069414584325
uint64_t = 5 (when and'ed)
uint = 5
Я подозреваю, что вы печатаете его также с форматной строкой меньшего размера. Когда вы делаете это, это на самом деле проблема выравнивания. Поскольку ваш процессор имеет младший порядок, он работает случайно (первые 32 бита 64-битного значения являются младшими значащими битами, 5
в приведенном выше примере).
Но он заполняет любые аргументы после , которые указывают в вашем printf, потому что вы поместили 64 бита в стек, а printf
потребляет только 32, следовательно, смещение.
См. здесь и здесь для более ранних ответов, объясняющих, как это работает (или, вернее, не работает).