Я скомпилировал этот код, используя Visual Studio 2010 (cl.exe /W4
) как файл C:
int main( int argc, char *argv[] )
{
unsigned __int64 a = 0x00000000FFFFFFFF;
void *orig = (void *)0xFFFFFFFF;
unsigned __int64 b = (unsigned __int64)orig;
if( a != b )
printf( " problem\ta: %016I64X\tb: %016I64X\n", a, b );
return;
}
Предупреждений нет, и в результате получается:
проблема a: 00000000FFFFFFFF b: FFFFFFFFFFFFFFFF
Полагаю, int orig = (int)0xFFFFFFFF
будет менее спорным, поскольку я не назначаю указатель на целое число.Однако результат будет таким же.
Может ли кто-нибудь объяснить мне, где в стандарте C рассматривается, что orig
- это знак, расширенный от 0xFFFFFFFF до 0xFFFFFFFFFFFFFFFF?
Я предположил, что (unsigned __int64)orig
станет 0x00000000FFFFFFFF.Похоже, что сначала выполняется преобразование в тип со знаком __int64, а затем оно становится без знака?
РЕДАКТИРОВАТЬ: на этот вопрос дан ответ в том, что указатели имеют расширенный знак, поэтому я вижу такое поведениев gcc и msvc.Однако я не понимаю, почему, когда я делаю что-то вроде (unsigned __int64)(int)0xF0000000
, его знак расширяется до 0xFFFFFFFFF0000000, но (unsigned __int64)0xF0000000
вместо этого не показывает то, что я хочу, а именно 0x00000000F0000000.
РЕДАКТИРОВАТЬ: ответ на вышеуказанное редактирование.Причина, по которой (unsigned __int64)(int)0xF0000000
является расширением знака, заключается в том, что, как отметил пользователь R :
Преобразование типа со знаком (или любого типа) в тип без знака всегда происходит через уменьшение по модулю один плюс максимальное значение целевого типа.
И в (unsigned __int64)0xF0000000
0xF0000000 начинается как целочисленный тип без знака, потому что он не может поместиться в целочисленный тип.Затем этот уже беззнаковый тип преобразуется unsigned __int64
.
. Итак, для меня это вывод с функцией, которая возвращает 32-битный или 64-битный указатель в виде unsigned __int64
для сравнения. Сначала я должен преобразовать32-битный указатель в моем 32-битном приложении на тип без знака перед повышением до unsigned __int64
.Результирующий код выглядит следующим образом (но, вы знаете, лучше):
unsigned __int64 functionidontcontrol( char * );
unsigned __int64 x;
void *y = thisisa32bitaddress;
x = functionidontcontrol(str);
if( x != (uintptr_t)y )
Снова отредактируйте: вот что я нашел в стандарте C99: 6.3.1.3 Целые числа со знаком и без знака
- 1 Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.
- 2 В противном случае,если новый тип является беззнаковым, значение преобразуется путем многократного сложения или вычитания значения, превышающего максимальное значение, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне нового типа.49)
- 3 В противном случае новый тип подписывается и значение не может быть представлено в нем;либо результат определяется реализацией, либо генерируется определяемый реализацией сигнал.
- 49) Правила описывают арифметику математического значения, а не значения выражения данного типа.