2015-10-30 4 views
2

Я немного смущен. Во время разработки одной функции, которая основывается на предопределенных параметрах, переходите к параметрам функции sprintf, необходимым по их типу, я нашел действительно странное поведение (что-то вроде «Это% f% d example», typeFloat, typeInt).Union float и int

Пожалуйста, обратите внимание на следующий раздели рабочий код:

struct Param { 
enum { typeInt, typeFloat } paramType; 
union { 
    float f; 
    int i; 
}; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
Param p; 
p.paramType = Param::typeInt; 
p.i = -10; 

char chOut[256]; 
printf("Number is %d\n", p.paramType == Param::typeInt ? p.i : p.f); 
printf("Number is %f\n", p.paramType == Param::typeInt ? p.i : p.f); 
return 0; 
} 

Мой ожидаемый результат будет для printf("Number is %d\n", p.paramType == Param::typeInt ? p.i : p.f);

Number is -10 

, но на самом деле напечатаны

Number is 0 

Я поставил точка останова после инициализации параметра p, и хотя p.paramType определяется как typeInt, фактический выход для if был -10.0000. Проверка p.f дает некоторое неопределенное значение, как ожидалось, и p.i показывает -10 также как и ожидалось. Но p.paramType == Param::typeInt ? p.i : p.f в окне просмотра оценивается в -10.000000.

Я добавил второй Printf, который печатает как поплавок, и теперь выход является

Number is 0 
Number is -10.000000 

Так на самом деле, почему это происходит? Возможно ли, что это ошибка в Visual Studio (я использую VS2012)?

Update:

std::cout<< (p.paramType == Param::typeInt ? p.i : p.f); 

дает правильное значение -10.

ответ

5

Это происходит потому, что в результате типа выражения p.paramType == Param::typeInt ? p.i : p.f всегда плавает (только значение отличаются в зависимости от paramType), но ваша первая строка формата ожидает целое число.

Следующие должны работать, как вы ожидаете:

printf("Number is %d\n", (int)(p.paramType == Param::typeInt ? p.i : p.f)); 

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

+0

Благодарим вас за ответ. Я не могу передать полное выражение в int как p.paramType также может быть float (я просто использовал int как пример выше). Почему он всегда плавает, если я подаю в целую часть объединения одно число? – Izzy

+1

Если вы не хотите передавать его в int, тогда нет смысла распечатывать его как целое. Поэтому либо всегда печатайте float, либо когда вы печатаете int, на самом деле даете ему int :-) Результат выражения (например, '?:') Может быть только одного типа; когда два подвыражения имеют разные типы, [выполняется неявное преобразование типа] (http://stackoverflow.com/q/8535226/21475). – Cameron

+0

А я вижу. Я узнал что-то новое сегодня :). Я не знал, что о тернарном утверждении может возвращаться только один тип. Но я не могу отличить все от int, потому что это может быть float вместо int. Решение состоит в том, чтобы оставить все плавающим и сделать формат как% .0f, который будет округлять число с плавающей точкой до целого числа. – Izzy

1

Проблема двоякая. Во-первых, это printf(). Не используйте printf() в коде C++. Причина связана со второй проблемой. printf() не имеет типа безопасность. Он не знает, какие типы вы ему дали.

Вторая причина заключается в том, как работают типы. Ваша тройная инструкция if всегда возвращает float, потому что это самый правый тип. Поскольку int может быть неявно преобразован в float, ничего «плохого» не происходит (если вы не включите различные «дополнительные» предупреждения). Итак, p.i преобразуется в float, но вы говорите printf(), ожидая int. Поэтому происходит неопределенное поведение. Ваша программа не авария, но она не дает вам то, что вы ожидали.

+0

Мне нравится 'printf', даже в C++. Это просто. Да, есть хороший аргумент с точки зрения безопасности, если вы не используете его должным образом, но этот аргумент можно расширить до довольно многого в C++ :-) – Cameron

+1

По-моему, использование 'std :: ostream' (например, через 'std :: cout') * также * просто. Это, безусловно, гораздо более расширяемо. – inetknght

+1

Очень верно. Тем не менее, я никогда не нуждался в расширяемости. – Cameron

Смежные вопросы