LINUX.ORG.RU

Преобразования типов в С/С++


0

0

Как в C/C++ отменить автоматическое преобразование типов?
Например:
void foo (int value);
....
foo ('a') - такая конструкция будет воспринята нормально. В результате value будет равно 97. А мне это очень не желательно.
Итак вопрос. Как от этого избавится?

С уважением, Солнышко

anonymous

Никак. А если не секрет какая принципиальная разница между: foo('a'); и foo(97);

?

anonymous
()

2 встречных вопроса?
1.  А почему нежелательно?
2.  В Си или в Си++? 

omerm
()

используй указатели, а не значения - на них ругается.

anonymous
()

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

justme
()

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

когда это не допустимо, например, чревато потерей данных, компайлер выдает warning или, если это строгий компайлер, error.

уровень "строгости" может задаваться в параметре и зависит от конкретного компайлера.

а избавиться от этого можно четко указывая тип (читай размер) константы, например, foo(97L);
тогда, если foo() - ожидает int, то компайлер выдаст warning/error на попытку передать ей 97L.

это было по сути вопроса.

а если говорить о хорошем тоне - то магические цифры вроде 97L в тексте программы использовать нежелательно. для этого существуют как define'ы так и глобальные константы.

proff
()

Менять язык - правильное решение. Советую посмотреть на Cyclone - тот же Цэ, только умный.

Antichrist
()

2proff: у компилятора C/C++ не возникает никаких проблем ни со стандартами, ни с совестью, когда он преобразовывает float в int, или int в char, насколько я помню. Warning'и он, по-моему, в этих случаях тоже не даёт, да и полагаться на одни warnings не солидно.

justme
()

чего-то я не пойму из-за чего весь сыр-бор, язык C++ различает int и char, но есть преобразования встроенных типов доставшиеся по-наследству от С, поэтому если тебе надо различать void foo(int); и void foo(char); то просто перегружаешь ее и имеешь 2 разные функции с одинаковым именем и разными прототипами...

PS. никого не удивляет, что есть cout << int(97); и cout << char(97); или char << 'a' и первый и второй операторы печатают разные вещи? :)

HTH

anonymous
()

чего-то я не пойму из-за чего весь сыр-бор, язык C++ различает int и char, но есть преобразования встроенных типов доставшиеся по-наследству от С, поэтому если тебе надо различать void foo(int); и void foo(char); то просто перегружаешь ее и имеешь 2 разные функции с одинаковым именем и разными прототипами...

PS. никого не удивляет, что есть cout << int(97); и cout << char(97); или char << 'a' и первый и второй операторы печатают разные вещи? :)

HTH

anonymous
()
Ответ на: комментарий от justme

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

если бы на самом деле все было бы так печально, то не было таких замечательных модулей как, например, <inttypes.h>.

это было первое.

а второе, так это вот что: не солидно Warning'и плодить. а если их в своих проектах не плодить, то и ориентироваться на них сразу станет возможным.

proff
()

Я не совсем понял, что уважаемый proff имеет в виду. Разумеется, компилятор может отличить char от int и float. Но если у него есть char, а ему нужен float то у него не возникает *абсолютно никаких* проблем с переводом (gcc-3.0, например, не выдаёт никаких warnings) - я только что ещё раз проверил.

Это, насколько я понял, и мешало тов. Солнышко.

А warning'и - вещь, безусловно, хорошая, но нестандартная. Один компилятор тебе warning напишет, другой - нет.

justme
()

для C++ на каждый тип данных создавать класс и определять операторы. соотв. в невозможных операторах делать вывод об ошибке.

lb
()
Ответ на: комментарий от justme

я же так с начал и написал: производится автоматическое преобразование типа когда это допутимо. например, допустимо преобразовать char к int и int к long, так как это не грозит потерей информации (преобразование ведется от меньшего типа к большему).

если это преобразование грозит потерей информации, то тут уже поведение зависит от компайлера, но наилучшее поведение - это error.

на самом деле, у вышеназванного тов. Солнышко есть некорректность в коде. что такое foo('a')? что за магическое чмсло 'f'? откуда оно взялось там, где int ожидается?

ему остается смириться с тем, что компайлер автоматом преобразовывает char к int (а он будет это делать, т.к. преобразование допустимое), либо код поправить. третье, как говорится, от лукавого;)

proff
()

Аа, так вот Вы про что :-) Ок. Сейчас проверил в другом направлении. При попытке сделать char из float он действительно ругается (выдаёт warning). Но сделать char из int, long, long long он позволяет без замечаний даже если включить ему -W -Wall -ansi -pedantic. Так что, полагаться на warnings нельзя. А error в таком случае компилятор просто не имеет права выдать, если он себя считает компилятором ANSI C++.

А проблема тов. Солнышко как раз и заключалась в "преобразованиях типа, когда это допустимо". На что ответ один - это не bug, а, к сожалению, feature. Поэтому можно либо обходить (писать всякие классы), либо менять язык.

Уф, надеюсь, разобрались.

justme
()
Ответ на: комментарий от justme

>Но сделать char из int, long, long long он позволяет без замечаний 
>даже если включить ему -W -Wall -ansi -pedantic. Так что, полагаться 
>на warnings нельзя. А error в таком случае компилятор просто не 
>имеет права выдать, если он себя считает компилятором ANSI C++. э

Вопреки распространенному мнению, -W -Wall включает _НЕ_ все
возможные предупреждения. Многие достаточно интересные виды
предупреждений требуют отдельного флага. Советую проконсультироватся
с man gcc.

Теперь к собственно subj:

В отличие от C, C++ поддерживает строгую типизацию. Поэтому
отменить преобразования типов, при желании, возможно.
В случае с C запретить преобразование невозможно, но gcc
может указать на возможные проблемы:

Пример 1:
Используем C, gcc:

int foo( char c )
{
    return (int)(2*c) ;
}

int 
main( int argc, char* argv[] )
{
     float f = 2.4 ;
     long  l = 10L ;
     char  c = 'a' ;
     
     foo( f ) ;
     foo( l ) ;
     foo( c ) ;      
}


Строим со следуещей строкой:

gcc -W -Wall -Wconversion 

Получаем примерно такие предупреждения:

warning: passing arg 1 of foo with different with due to prototype
warning: passing arg 1 of foo as integer rather than floating due
         to prototype.


Пример 2:
C++, gcc

template < typename T, typename FT >
FT safe_apply( FT (*f)( T ), T t )
{
    return (*f)( t ) ;
}

int foo( char c )
{
    return static_cast< int > ( 2 * c ) ;
}

int 
main( int argc, char* argv[] )
{
    float f = 2.4 ;
    long  l = 10L ;
    char  c = 'a' ;

// safe_apply отменяет неявное преобразование типа.
    safe_apply( foo, f ) ;
    safe_apply( foo, l ) ;
    safe_apply( foo, c ) ;    
}

Программа не пройдет компиляцию.

omerm
()

А например если сделать функцию, которая будет принимать ссылку на то, что надо: обычно компилеры ругаются, когда им на ссылку не то подсовываешь. Правда если она константная то часть ругательств будет выключена...

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.