LINUX.ORG.RU

char = char * char как?!


1

1

Доброго времени суток! Есть задание на С, надо просто вывести на экран чар, как произведение двух чаров. Пример:

char a,b,c;

int main (){

printf(«%c», a);

printf(«%c», b);

c=a*b;

printf(«%c», c);

}

После первого printf консоль вылетает, что-то не так, но getchar работает, хмм. Поскольку конечное значение char, то после перемножения, он выдает не число интегером, а символы. Как присвоить чару, модуль произведия двух чаров, не изменяя его тип данных, то есть сохранить формат char?

Спасибо!



Последнее исправление: maxylopes (всего исправлений: 1)
Ответ на: комментарий от drBatty

Ещё один оратор костыльности x86, только почему то никто из них не предлагает альтернативу, как кстати у вас, можете предложить замену?

bhfq ★★★★★
()
Ответ на: комментарий от drBatty

вот какой код я получил при сложении двух char'ов:

 8048434:       8a 54 24 1f             mov    dl,BYTE PTR [esp+0x1f]
 8048438:       8a 44 24 1e             mov    al,BYTE PTR [esp+0x1e]
 804843c:       01 d0                   add    eax,edx
 804843e:       88 44 24 1d             mov    BYTE PTR [esp+0x1d],al
Очевидно, что преобразования в int тут НЕТ. Т.е. вообще нет. Складываются только байты, и результат тоже записывается в виде байта. Несмотря на то, что команда сложения 32х битная, но в 24х старших битах складывается мусор, который никого не волнует.

drBatty ★★
()
Ответ на: комментарий от bhfq

Ещё один оратор костыльности x86,

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

только почему то никто из них не предлагает альтернативу, как кстати у вас, можете предложить замену?

зачем? мне нравится.

drBatty ★★
()
Ответ на: комментарий от vvviperrr

Вообще всё это похоже на несмешной цирк.

Один не может дать ссылку на конкретный параграф спецификации, другой — бредит листингами ассемблера.

geekless ★★
()
Последнее исправление: geekless (всего исправлений: 1)
Ответ на: комментарий от geekless

Друг мой, вы что-нибудь слышали об оптимизациях?

О да. Как я забыть-то мог? Хорошо, gcc -O0

 8048434:       8a 54 24 1f             mov    dl,BYTE PTR [esp+0x1f]
 8048438:       8a 44 24 1e             mov    al,BYTE PTR [esp+0x1e]
 804843c:       01 d0                   add    eax,edx
 804843e:       88 44 24 1d             mov    BYTE PTR [esp+0x1d],al
нет разницы. Что в общем-то неудивительно - я и в первый раз компиллил без оптимизации(так по дефолту).

Оппоненты настаивают на том, что дескать стандарт велит в int преобразовывать, а я на том, что компилятор считает так, как его левая пятка захочет, и стандарт НИЧЕГО не требует, кроме того, что-бы результат был «верным». В данном случае мы конечно получаем 32 бита результата, но 24 из них - неправильные, и содержат случайный мусор. Истинны только 8 бит результата, которые и используются.

drBatty ★★
()
Ответ на: комментарий от geekless

Один не может дать ссылку на конкретный параграф спецификации

ну я честно сказал - я не нашёл. Очевидно - НЕТУ.

другой — бредит листингами ассемблера.

что ты имеешь против ассемблера? И как ещё доказать, что происходит, а чего не происходит IRL?

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

-O0

Это настолько примитивная оптимизация, что никакой -O0 не гарантирует её отсутствия.

Оппоненты настаивают на том, что дескать стандарт

Кто-нибудь из вас двоих пробовал этот стандарт читать?

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

Это настолько примитивная оптимизация, что никакой -O0 не гарантирует её отсутствия.

потому-что это даже не оптимизация. Это вроде как x++, ну какой идиот будет разворачивать x++ в

tmp = x;
x = tmp + 1;
return tmp;
Если в архитектуре есть инкремент, и кроме того результат не нужен, а нужен только побочный эффект? Вот никто и не разворачивает...

А сама команда оттуда же, откуда это «во многих случаях преобразуется в int», именно из тех самых PDP-11. Вот там действительно можно было одной командой записать x = array[index++]; Ну вот K&R и зафигачили x++ в язык. Ну и что? Из-за этого теперь что, всё делать через временную переменную, а потом то, что получилось оптимизировать?

drBatty ★★
()
Ответ на: комментарий от geekless

Ты б еще хаскельные листинги ассемблера поизучал...

сишные листинги асма показывают, как нужно писать на C, а как - не нужно.

хаскельные листинги доказывают, что хаскел не нужен.

drBatty ★★
()
Ответ на: комментарий от geekless

я тебе дал ссылку на мой пост, где была дана ссылка на правила продвижения типов, где и был указан параграф стандарта

http://www.eskimo.com/~scs/cclass/int/sx4cb.html

The rules, then (which you can also find on page 44 of K&R2, or in section 6.2.1 of the newer ANSI/ISO C Standard) are approximately as follows:

in section 6.2.1 of the newer ANSI/ISO C Standard

6.2.1

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

ссылка на ссылку

Какое вопиющее неуважение к Ъ.

6.2.1

6.2.1 Scopes of identifiers
1 An identifier can denote an object; a function; a tag or a member of a structure, union, or
 enumeration; a typedef name; a label name; a macro name; or a macro parameter. The
same identifier can denote different entities at different points in the program. A member
of an enumeration is called an enumeration constant. Macro names and macro
parameters are not considered further here, because prior to the semantic phase of
program translation any occurrences of macro names in the source file are replaced by the
preprocessing token sequences that constitute their macro definitions.

2 For each different entity that an identifier designates, the identifier is visible (i.e., can be
 used) only within a region of program text called its scope. Different entities designated
by the same identifier either have different scopes, or are in different name spaces. There
are four kinds of scopes: function, file, block, and function prototype. (A function
prototype is a declaration of a function that declares the types of its parameters.)

3 A label name is the only kind of identifier that has function scope. It can be used (in a
 goto statement) anywhere in the function in which it appears, and is declared implicitly
by its syntactic appearance (followed by a : and a statement).

4 Every other identifier has scope determined by the placement of its declaration (in a
 declarator or type specifier). If the declarator or type specifier that declares the identifier
appears outside of any block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit. If the declarator or type specifier that
declares the identifier appears inside a block or within the list of parameter declarations in
a function definition, the identifier has block scope, which terminates at the end of the
associated block. If the declarator or type specifier that declares the identifier appears
within the list of parameter declarations in a function prototype (not part of a function
definition), the identifier has function prototype scope, which terminates at the end of the
function declarator. If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will be a
strict subset of the scope of the other entity (the outer scope). Within the inner scope, the
identifier designates the entity declared in the inner scope; the entity declared in the outer
scope is hidden (and not visible) within the inner scope.

5 Unless explicitly stated otherwise, where this International Standard uses the term
 ‘‘identifier’’ to refer to some entity (as opposed to the syntactic construct), it refers to the
        entity in the relevant name space whose declaration is visible at the point the identifier
       occurs.

6 Two identifiers have the same scope if and only if their scopes terminate at the same
 point.

7 Structure, union, and enumeration tags have scope that begins just after the appearance of
 the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.

Где?

geekless ★★
()
Ответ на: комментарий от hexdump01010101

Cпасибо за помощь все как работало так и работает, но не мог бы ты объяснить, что конкретно происходит при

char x = x - '0'; ?

Я понимаю для чего, но не понимаю, что конкретно происходит ч чаром. И вы все продолжаете дискуссию про присвоение типов. Когда я пишу

char x,y,z;

x=y*z;

printf(«result is %i», x)

Означает ли это, что я поменял тип переменной на интегер? Или это просто функция для принтф, которая говорит о том, как вывести переменную?

maxylopes
() автор топика
Ответ на: комментарий от geekless

я не нашёл

Я вот тоже не нашел.

Плохо искали:

N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x

6.3.1 Arithmetic operands
6.3.1.1 Boolean, characters, and integers
2
The following may be used in an expression wherever an int or unsigned int may
be used:
— An object or expression with an integer type (other than int or unsigned int)
whose integer conversion rank is less than or equal to the rank of int and
unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a
bit-field), the value is converted to an int; otherwise, it is converted to an unsigned
int. These are called the integer promotions. All other types are unchanged by the
integer promotions.


6.3.1.8 Usual arithmetic conversions
1
Many operators that expect operands of arithmetic type cause conversions and yield result
types in a similar way. The purpose is to determine a common real type for the operands
and result. For the specified operands, each operand is converted, without change of type
domain, to a type whose corresponding real type is the common real type. Unless
explicitly stated otherwise, the common real type is also the corresponding real type of
the result, whose type domain is the type domain of the operands if they are the same,
and complex otherwise. This pattern is called the usual arithmetic conversions:
First, if the corresponding real type of either operand is long double, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is long double.
Otherwise, if the corresponding real type of either operand is double, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is double.
Otherwise, if the corresponding real type of either operand is float, the other
operand is converted, without change of type domain, to a type whose
corresponding real type is float.
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
...

При этом явно оговорено:

§5.1.2.3 Environment

EXAMPLE 2
In executing the fragment
char c1, c2;
/* ... */
c1 = c1 + c2;
the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size
and then add the two ints and truncate the sum. Provided the addition of two chars can be done without
overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only
produce the same result, possibly omitting the promotions.
LamerOk ★★★★★
()

проги пишу в codeblocks (все работает, конфетка), у профессора MC Visual C++ и он всех заставляет, проги точить под его компилятор. Не проблема все работает, но бесит этот ворнинг!

warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS

Заменяю scanf на scanf_s получаю windows error «Access violation»... так бесит этот мс.

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