Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 15.03.2014, 21:22   #1
J1Mmy
Пользователь
 
Аватар для J1Mmy
 
Регистрация: 10.05.2012
Сообщений: 24
По умолчанию Реакция разных компиляторов на unsigned short

Всем доброго времени суток. На днях столкнулся с непредсказуемым поведением компиляторов на переменную типа unsigned short. Собственно имелся такой код:
Код:
#include <stdio.h>
#include <conio.h>

#pragma argsused

int main(void)
{
	char PhotoSize;
	unsigned short PhotoCount;
	float TotalSum, Discount;
	printf("Please, choose photo size:\n1 - 9x12(3.5$ per 1)\n2 - 10x15(4.5$ per 1)\n3 - 18x24(6$ per 1)\nYour choise -> ");
	scanf("%d", &PhotoSize);
	printf("Please, enter photos count -> ");
	scanf("%d", &PhotoCount);
	printf("===========================\n");
	switch (PhotoSize)
		{
		case 1: TotalSum = PhotoCount*3.5;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 3.5$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		case 2: TotalSum = PhotoCount*4.5;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 4.5$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		case 3: TotalSum = PhotoCount*6;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 6$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		default: printf("There is no such option");
		}
	return 0;
}
При компиляции в DJGPP(v 2.95.3) и компилятора из пакета Qt Creator на присваивание переменной PhotoSize с помощью scanf() или на этапе инициализации ничего не происходило, т.е значение переменной равно 0.
При компиляции через VS или на сайте codeforces программа функционировала нормально. По совету знакомого поменял unsigned short на int, хотя вроде как это относится к переменной PhotoCount и не должно быть связано c PhotoSize...

Собственно сам вопрос: Как может быть связан тип переменной с компилятором, как может "неверный" тип переменной влиять на исполнение программы в целом?
J1Mmy вне форума Ответить с цитированием
Старый 16.03.2014, 01:23   #2
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Возможно это связанно с типом переменной
Код:
char PhotoSize;
Функция
Код:
scanf("%d", &PhotoSize);
думает, что аргумент - это "число", а не "символ", ведь для символа нужно указывать:

Цитата:
specifier
c
Description
Character

Characters extracted
The next character. If a width other than 1 is specified, the function reads exactly width characters and stores them in the successive locations of the array passed as argument. No null character is appended at the end.
Но вы указали "%d"

Цитата:
specifier
d
Description
Decimal integer

Characters extracted
Any number of decimal digits (0-9), optionally preceded by a sign (+ or -).
Предлагаю вам заменить типы на int или unsigned int
_Bers вне форума Ответить с цитированием
Старый 16.03.2014, 10:41   #3
J1Mmy
Пользователь
 
Аватар для J1Mmy
 
Регистрация: 10.05.2012
Сообщений: 24
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Возможно это связанно с типом переменной
Код:
char PhotoSize;
Функция
Код:
scanf("%d", &PhotoSize);
думает, что аргумент - это "число", а не "символ", ведь для символа нужно указывать:



Но вы указали "%d"



Предлагаю вам заменить типы на int или unsigned int

С этим не как не связано. Ставил и int, и short - программа не хотела правильно работать, до тех пор пока тип unsigned short у PhotoCount не задал.
Char можно использовать как и символьный тип, так и целочисленный(что вызывает у меня когнитивный диссонанс).

Последний раз редактировалось J1Mmy; 16.03.2014 в 10:46.
J1Mmy вне форума Ответить с цитированием
Старый 16.03.2014, 11:23   #4
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

2J1Mmy
ты объявляешь переменную одним типом (char или unsigned short), а scanf-у просишь считать значение РАЗМЕРОМ int. если у тебя переменная unsigned short - считывай ее так: scanf("%hu", &i) (от half unsigned). если хочешь считать unsigned char - "%hhu" (half half unsigned).

написал код с UB и ругает компиляторы. ну что за люди
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance
pproger вне форума Ответить с цитированием
Старый 16.03.2014, 11:30   #5
J1Mmy
Пользователь
 
Аватар для J1Mmy
 
Регистрация: 10.05.2012
Сообщений: 24
По умолчанию

Цитата:
Сообщение от pproger Посмотреть сообщение
2J1Mmy
ты объявляешь переменную одним типом (char или unsigned short), а scanf-у просишь считать значение РАЗМЕРОМ int. если у тебя переменная unsigned short - считывай ее так: scanf("%hu", &i) (от half unsigned). если хочешь считать unsigned char - "%hhu" (half half unsigned).

написал код с UB и ругает компиляторы. ну что за люди
Тогда почему с таким кодом всё работает?
Код:
#include <stdio.h>
#include <conio.h>

#pragma argsused

int main(void)
{
	char PhotoSize;
	int PhotoCount;
	float TotalSum, Discount;
	printf("Please, choose photo size:\n1 - 9x12(3.5$ per 1)\n2 - 10x15(4.5$ per 1)\n3 - 18x24(6$ per 1)\nYour choise -> ");
	scanf("%d", &PhotoSize);
	printf("Please, enter photos count -> ");
	scanf("%d", &PhotoCount);
	printf("===========================\n");
	switch (PhotoSize)
		{
		case 1: TotalSum = PhotoCount*3.5;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 3.5$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		case 2: TotalSum = PhotoCount*4.5;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 4.5$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		case 3: TotalSum = PhotoCount*6;
			Discount = (PhotoCount > 10)?(TotalSum/10):(0);
			printf("Cost: 6$\nCount: %d\nTotal Sum: %.2f\nDiscount: %.2f\nEnd Sum: %.2f", PhotoCount, TotalSum, Discount, TotalSum - Discount); break;
		default: printf("There is no such option");
		}
	return 0;
}
А ведь разница всего лишь в int PhotoCount;.
И я не ругаю компилятор, а меня интересует вопрос, почему так поразному реагируют компиляторы на один и тот же код.

P.S: За %hu и %hhu спасибо. Не знал, что спецификаторы можно повторять несколько раз.

Последний раз редактировалось J1Mmy; 16.03.2014 в 11:39.
J1Mmy вне форума Ответить с цитированием
Старый 16.03.2014, 11:40   #6
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

2J1Mmy
рассмотрим такой пример

// КОД с UB
Код:
#include <stdio.h>

int main(int argc, char *argv[]) {
	char PhotoSize = 0;
	short PhotoCount = 0;

	scanf("%d", &PhotoSize);
	printf("%d %d\n", PhotoSize, PhotoCount);
	scanf("%d", &PhotoCount);
	printf("%d %d\n", PhotoSize, PhotoCount);

	return 0;
}
вывод
Цитата:
viper@air-viper ~]$ ./a.out
1
1 0
2
0 2
как ты видишь, твоя char переменная корректно считывается. далее, ты считываешь short, но в scanf передаешь %d - указание, что нужно считать int. он считывает int и записывает в short, попутно перезатирая char.

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

да, в случае твоего примера. ты объявил char и int. в обоих случаях считываешь %d. char у тебя после ввода int не перезатирается, но ты перезатираешь что-то другое, что находится выше char по стеку.
пример:

// КОД с UB
Код:
#include <stdio.h>

int main(int argc, char *argv[]) {
	char some_stuff = 100;
	char PhotoSize = 0;
	int PhotoCount = 0;

	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);

	scanf("%d", &PhotoSize);
	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);
	scanf("%d", &PhotoCount);
	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);

	return 0;
}
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance

Последний раз редактировалось pproger; 16.03.2014 в 11:46.
pproger вне форума Ответить с цитированием
Старый 16.03.2014, 12:04   #7
J1Mmy
Пользователь
 
Аватар для J1Mmy
 
Регистрация: 10.05.2012
Сообщений: 24
По умолчанию

Цитата:
Сообщение от pproger Посмотреть сообщение
2J1Mmy
рассмотрим такой пример

// КОД с UB
Код:
#include <stdio.h>

int main(int argc, char *argv[]) {
	char PhotoSize = 0;
	short PhotoCount = 0;

	scanf("%d", &PhotoSize);
	printf("%d %d\n", PhotoSize, PhotoCount);
	scanf("%d", &PhotoCount);
	printf("%d %d\n", PhotoSize, PhotoCount);

	return 0;
}
вывод

как ты видишь, твоя char переменная корректно считывается. далее, ты считываешь short, но в scanf передаешь %d - указание, что нужно считать int. он считывает int и записывает в short, попутно перезатирая char.

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

да, в случае твоего примера. ты объявил char и int. в обоих случаях считываешь %d. char у тебя после ввода int не перезатирается, но ты перезатираешь что-то другое, что находится выше char по стеку.
пример:

// КОД с UB
Код:
#include <stdio.h>

int main(int argc, char *argv[]) {
	char some_stuff = 100;
	char PhotoSize = 0;
	int PhotoCount = 0;

	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);

	scanf("%d", &PhotoSize);
	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);
	scanf("%d", &PhotoCount);
	printf("%d %d %d\n", PhotoSize, PhotoCount, some_stuff);

	return 0;
}
Теперь понял о чем речь. Спасибо за подробное разъяснение! Впредь буду осторожнее с кодом.
J1Mmy вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Компиляторы компиляторов(генераторы парсеров) Пепел Феникса Общие вопросы по программированию, компьютерный форум 6 14.12.2011 20:53
Для типов данных char, short, int, long с квалификаторами signed, unsigned составить программу, которая, listiksasha Фриланс 4 21.02.2011 12:26
Для типов данных char, short, int, long с квалификаторами signed, unsigned составить программу, которая, listiksasha Помощь студентам 2 20.02.2011 12:57
Сравнение скорости компиляторов Umen Обсуждение статей 13 05.10.2009 19:48