Печать типа int с %lu - C+XINU

У меня есть данный код, по-моему, с этим кодом что-то не так: компилирую под XINU.

Важны следующие переменные:

unsigned long ularray[];
int num;
char str[100];

Есть функция, возвращающая int:

int func(int i)
{
    return ularray[i];
}

теперь код такой:

num = func(i);
sprintf(str, "number = %lu\n", num);
printf(str);

Проблема в том, что я получаю большие числа при печати с помощью %lu, что неверно.

Если я изменю %lu на %d, я получу правильный номер. Например: с %lu я получаю 27654342, а с %d я получаю 26, последнее верно;

Даны переменные, дано объявление функции, я пишу тело, но оно должно возвращать int;

Мои вопросы:

  1. Я не знаком с 'sprintf', может, проблема в нем?

  2. Я назначил unsigned long для int, а затем распечатал int с помощью %lu, это правильно?

  3. Как я могу решить проблему?

Заранее спасибо.

Спасибо всем за ответ. Я просто хочу отметить, что я работаю под XINU, ну, я изменил порядок компиляции файлов и, что вы знаете... он работает и показывает одинаковые числа на %lu и %d.

Я хорошо знаю, что присвоение «unsigned long» для int и последующая печать с использованием %lu является неправильным кодированием и может привести к потере данных. Но, как я уже сказал, код указан, я не мог изменить переменные и команду печати.

Кстати, у меня не было ошибок или предупреждений. Я понятия не имею, почему изменение порядка компиляции решило проблему, если у кого-то есть идея, которой вы можете поделиться.

Я хочу поблагодарить всех вас, кто пытался мне помочь.


person avi.tavdi    schedule 25.08.2012    source источник
comment
Почему вы транслируете на int? PS "%lu" является подходящим спецификатором формата для unsigned long... "%d" обрабатывает аргумент как signed int, что работает здесь, поскольку num равно signed int. Вы должны быть осторожны при смешивании такой подписи.   -  person obataku    schedule 25.08.2012
comment
Почему именно вы не используете %d? Тот факт, что вы получаете разные результаты, перемещая код, показывает, что вы делаете что-то неправильно (осознанно тоже - нехорошо). Какую часть кода нельзя изменить?   -  person Mat    schedule 25.08.2012


Ответы (4)


Я назначил unsigned long для int, а затем распечатал int с помощью %lu, это правильно?

Нет, это вообще не правильно. Подумай немного! Printf пытается получить доступ к памяти, представленной переменными, которые вы передаете, и в вашем случае unsigned long представлен в большем количестве битов, чем int, поэтому, когда printf предлагается напечатать unsigned int, он прочитает ваш фактический int и прочитает некоторые другая память, которая, вероятно, является мусором, отсюда и случайные числа. Если бы у printf был прототип, точно упоминающий unsigned long, компилятор мог бы выполнить неявное приведение и заполнить остальную часть нежелательной памяти нулями, но, поскольку это не так, вам нужно выполнить одно из следующих решений:

Один, явный бросок вашей переменной:

printf("%lu", (unsigned long)i);

Во-вторых, используйте правильный спецификатор формата:

printf("%d", i);

Также есть проблемы с присвоением unsigned long типу int — если long содержит слишком большое число, то он не влезет в int и будет усечен.

person Community    schedule 25.08.2012

1) недоразумение - спецификаторы формата вообще

2) num - это int, поэтому %d является правильным, когда int - это то, что вы хотите напечатать.

3) в идеале

  • int func(int i) будет unsigned long func(size_t i)
  • а int num будет unsigned long num
  • а sprintf(str, "number = %d\n", num); будет sprintf(str, "number = %lu\n", num);

таким образом, не будет сужения и преобразований - тип/значения будут корректно сохраняться на протяжении всего выполнения.

и, чтобы быть педантичным, printf должно быть printf("%s", str);

если вы повысите уровень предупреждений, ваш компилятор предупредит вас о некоторых из этих вещей. я занимаюсь программированием в течение долгого времени, и я все еще оставляю уровень предупреждения неприемлемо высоким (по стандартам некоторых людей).

person justin    schedule 25.08.2012
comment
Я отредактировал свой вопрос, и моя проблема была решена, спасибо за ответ. - person avi.tavdi; 25.08.2012

Если у вас есть int, используйте %d (или %u для беззнакового целого числа). Если у вас есть тип long, используйте %ld (или %lu для unsigned long).
Если вы скажете printf, что вы даете ему тип long, но передадите только целое число, вы напечатаете случайный мусор. (Технически это было бы неопределенным поведением.)

Неважно, что это int как-то "пришло" из длинного. Как только вы присвоите его чему-то более короткому, лишние байты будут потеряны. У вас осталось только int.

person Mat    schedule 25.08.2012
comment
Используйте "%ld", только если вы используете signed long int. - person obataku; 25.08.2012
comment
long int подписано. Так что лучше использовать %lu для unsigned long int. - person Mat; 25.08.2012
comment
Я знаю, что long int это signed long int, но вы должны различать, когда использовать "%ld"/"%li" и "%lu" - person obataku; 25.08.2012

Я назначил unsigned long для int, а затем распечатал int с помощью %lu, это правильно?

Нет, и я предлагаю сначала не приводить к типу int или просто использовать int в качестве типа массива. Кажется бессмысленным хранить гораздо большее представление и использовать только меньшее. В любом случае результаты спринта всегда будут неверными, пока вы правильно не сопоставите тип (технически кодировку) переменной с спецификатором преобразования формата. Это означает, что если вы передаете unsigned long, используйте %ul, если это int, используйте либо %i, либо %d (разница в том, что %d всегда base-10, %i может принимать дополнительные спецификаторы для печати в другие базы.

Как я могу решить проблему?

Измените возврат вашей функции и кодировку num на unsigned long

unsigned long ularray[];
unsigned long num;
char str[100];

unsigned long func(int i)
{
    return ularray[i];
}
person Chris Trahey    schedule 25.08.2012