Вы кодируете ' греховно ' (совершая ряд ошибок, которые рано или поздно причинят вам боль - в основном раньше). Во-первых, вы предполагаете, что целое число имеет правильный порядковый номер. На некоторых машинах вы будете неправы - либо на машинах Intel, либо на машинах PowerPC или SPARC.
В общем, вы должны показывать реальные результаты, которые вы получаете, а не просто говорить, что вы получаете неправильный результат; Вы также должны показать ожидаемый результат. Это помогает людям отлаживать ваши ожидания.
Вот моя модифицированная версия вашего кода - вместо запроса ввода она просто принимает указанное вами значение.
#include <stdio.h>
int main(void)
{
unsigned int c = 2249459722;
unsigned char* cptr = (unsigned char*)&c;
printf("Integer value: %10u\n", c);
printf("Integer value: 0x%08X\n", c);
printf("Dotted decimal: %u.%u.%u.%u \n", *cptr, *(cptr+1), *(cptr+2), *(cptr+3));
return(0);
}
При компиляции на моем Mac (Intel, little-endian) вывод:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Когда компилируется на моем Sun (SPARC, big-endian), вывод:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 134.20.8.10
(Используя GCC 4.4.2 на SPARC, я получаю предупреждение:
xx.c:4: warning: this decimal constant is unsigned only in ISO C90
Использование GCC 4.2.1 на Mac - с большим количеством включенных предупреждений (gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Werror
) - я не получаю это предупреждение, что интересно.) Я могу удалить это, добавив суффикс U
к целочисленной константе .
Другой способ взглянуть на проблемы иллюстрируется следующим кодом и чрезвычайно суетливыми настройками компилятора, показанными выше:
#include <stdio.h>
static void print_value(unsigned int c)
{
unsigned char* cptr = (unsigned char*)&c;
printf("Integer value: %10u\n", c);
printf("Integer value: 0x%08X\n", c);
printf("Dotted decimal: %u.%u.%u.%u \n", *cptr, *(cptr+1), *(cptr+2), *(cptr+3));
}
int main(void)
{
const char str[] = "2249459722";
unsigned int c = 2249459722;
printf("Direct operations:\n");
print_value(c);
printf("Indirect operations:\n");
if (sscanf("2249559722", "%d", &c) != 0)
printf("Conversion failed for %s\n", str);
else
print_value(c);
return(0);
}
Не удается скомпилировать (из-за настройки -Werror
) сообщение:
cc1: warnings being treated as errors
xx.c: In function ‘main’:
xx.c:20: warning: format ‘%d’ expects type ‘int *’, but argument 3 has type ‘unsigned int *’
Удалите настройку -Werror
, и она скомпилируется, но затем отобразит следующую проблему, которая у вас возникла - не проверять наличие ошибок в функциях, которые могут дать сбой:
Direct operations:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations:
Conversion failed for 2249459722
По сути, функция sscanf()
сообщает, что ей не удалось преобразовать строку в целое число со знаком (поскольку значение слишком велико, чтобы уместиться - см. Предупреждение из GCC 4.4.2), но ваш код не проверял наличие ошибка возврата из sscanf()
, поэтому вы использовали любое значение, оставленное в c
на тот момент.
Итак, в вашем коде много проблем:
- Предполагается, что определенная архитектура (с прямым порядком байтов вместо того, чтобы признавать, что байты с прямым порядком байтов также существуют).
- Он не компилируется чисто при использовании компилятора с большим количеством предупреждений - по уважительной причине.
- Он не проверяет, что функции, которые могут выйти из строя, действительно были успешными.
Комментарий Алока
Да, проверка на sscanf()
неверна. Вот почему у вас есть обзоры кода, а также почему это помогает опубликовать код, который вы тестируете.
Теперь я немного озадачен - получаю последовательное поведение, которое не могу сразу объяснить. С очевидной ревизией (тестирование на MacOS X 10.6.2, GCC 4.2.1, 32-битные и 64-битные компиляции) я получил один не очень вменяемый ответ. Когда я переписываю более модульно, я получаю здравый ответ.
+ cat yy.c
#include <stdio.h>
static void print_value(unsigned int c)
{
unsigned char* cptr = (unsigned char*)&c;
printf("Integer value: %10u\n", c);
printf("Integer value: 0x%08X\n", c);
printf("Dotted decimal: %u.%u.%u.%u \n", *cptr, *(cptr+1), *(cptr+2), *(cptr+3));
}
int main(void)
{
const char str[] = "2249459722";
unsigned int c = 2249459722;
printf("Direct operations:\n");
print_value(c);
printf("Indirect operations:\n");
if (sscanf("2249559722", "%d", &c) != 1)
printf("Conversion failed for %s\n", str);
else
print_value(c);
return(0);
}
+ gcc -o yy.32 -m32 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes yy.c
yy.c: In function ‘main’:
yy.c:20: warning: format ‘%d’ expects type ‘int *’, but argument 3 has type ‘unsigned int *’
+ ./yy.32
Direct operations:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations:
Integer value: 2249559722
Integer value: 0x86158EAA
Dotted decimal: 170.142.21.134
У меня нет хорошего объяснения значения 170.142.21.134; но это соответствует моей машине, на данный момент.
+ gcc -o yy.64 -m64 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes yy.c
yy.c: In function ‘main’:
yy.c:20: warning: format ‘%d’ expects type ‘int *’, but argument 3 has type ‘unsigned int *’
+ ./yy.64
Direct operations:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations:
Integer value: 2249559722
Integer value: 0x86158EAA
Dotted decimal: 170.142.21.134
То же значение - даже в 64-битной версии вместо 32-битной. Возможно, проблема в том, что я пытаюсь объяснить неопределенное поведение, которое по определению более или менее необъяснимо (необъяснимо).
+ cat xx.c
#include <stdio.h>
static void print_value(unsigned int c)
{
unsigned char* cptr = (unsigned char*)&c;
printf("Integer value: %10u\n", c);
printf("Integer value: 0x%08X\n", c);
printf("Dotted decimal: %u.%u.%u.%u \n", *cptr, *(cptr+1), *(cptr+2), *(cptr+3));
}
static void scan_value(const char *str, const char *fmt, const char *tag)
{
unsigned int c;
printf("Indirect operations (%s):\n", tag);
fmt = "%d";
if (sscanf(str, fmt, &c) != 1)
printf("Conversion failed for %s (format %s \"%s\")\n", str, tag, fmt);
else
print_value(c);
}
int main(void)
{
const char str[] = "2249459722";
unsigned int c = 2249459722U;
printf("Direct operations:\n");
print_value(c);
scan_value(str, "%d", "signed");
scan_value(str, "%u", "unsigned");
return(0);
}
Использование аргумента функции, подобного этому, означает, что GCC больше не может определить фиктивный формат.
+ gcc -o xx.32 -m32 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes xx.c
+ ./xx.32
Direct operations:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations (signed):
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations (unsigned):
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Результаты согласуются здесь.
+ gcc -o xx.64 -m64 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes xx.c
+ ./xx.64
Direct operations:
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations (signed):
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
Indirect operations (unsigned):
Integer value: 2249459722
Integer value: 0x8614080A
Dotted decimal: 10.8.20.134
И это то же самое, что и 32-разрядный корпус. Я официально ошеломлен. Основные наблюдения остаются точными - будьте внимательны, учитывайте предупреждения компилятора (и извлекайте предупреждения компилятора) и не предполагайте, что «весь мир работает на чипах Intel» (раньше это было «не предполагайте, что весь мир VAX ", давным-давно!).