Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Сумма трех байт

Ответить
Настройки темы
Сумма трех байт

Пользователь


Сообщения: 135
Благодарности: 0

Профиль | Отправить PM | Цитировать


Небольшая програмка на Си
Сумма трех байт: (Компилировалась на VC6)
Код: Выделить весь код
char buf[] = {1,4,16};
char *p= buf;

int Sum1 = *(p++) + *(p++) + *(p++);

p= buf-1;
int Sum2 = *(++p) + *(++p) + *(++p);

printf("Sum1=%d *** Sum2=%d\n", Sum1,Sum2);
При компиляции в Debug выдает:
Цитата:
Sum1=3 *** Sum2=21
В Release:
Цитата:
Sum1=3 *** Sum2=48
  1. Почему программка ведет себя по разному в Debug и в Release?
  2. Почему она неправильно в 3-ех случаях из 4 подсчитывает сумму?
    Должно быть 21 в смысле: buf[0]+buf[1]+buf[2]  = 21

Отправлено: 03:14, 25-09-2003

 

Старожил


Сообщения: 167
Благодарности: 0

Профиль | Отправить PM | Цитировать


bilytur
Кофе попей, протри глаза, и внимательно посмотри, ЧТО ты складываешь:
В первом случае ты складываешь, то что надо - buf[0]+buf[1]+buf[2]    (p=buf)
Во втором случае buf[-1]+buf[0]+buf[1]     (p=buf-1   )
Так как buf[-1] имеет неопределённое значение, у тебя получаются разные результаты.

Добавлено:

bilytur
Советую также обратить внимание (во избежание другого глюка) на то, что у тебя результат будет CHAR, а не INT, как ты хотел (если ты именно так хотел), возникнет переполнение. Чтобы этого избежать, надо написать int Sum1 = int(*(p++)) + *(p++) + *(p++);

Отправлено: 04:20, 25-09-2003 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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


Аватара для shurikan

Старожил


Сообщения: 240
Благодарности: 1

Профиль | Отправить PM | Цитировать


Sarge
Чё-то у тебя со знанием языка не того... Про постфиксные и префиксные операции слышал чего-нибудь? Сумма char-ов - действительно имеет тип char, н6о это если в арифметическом выражении не присутствуют операнды других типов, тогда будет сделано приведение типов. А здесь приведение производится при присваивании. Вопрос был почему написанное не даёт правильный результат?
bilytur
Трудно так сразу сказать. Я бы скомпилировал в ассемблер, и посмотрел, чё там VC имеет ввиду, обрабатывая этот текст. Там можно будет понять, когда он указатели продвигает, и на что они в тот момент указывают.


Добавлено:

А вообще C/C++ не любит таких наворотов. Он проводит оптимизацию при компиляции, а поскольку в выражении все операции равноправны, он может вычислять их в любом порядке, а не слева направо. И, казалось бы, да складывай их в любом порядке, они же одинаковые (операнды, я имею ввиду), но там ещё указатель перемещается, а это он как-то не очень любит. Так что, скомпили в ассемблер...

-------
UNIX, UNAS и др. Myself I'll like 'em


Отправлено: 06:44, 25-09-2003 | #3


Новый участник


Сообщения: 49
Благодарности: 0

Профиль | Отправить PM | Цитировать


Ассемблер рулез
Скомпилил твой пример и как оказалось в релизе сложения нет вообще. Вот сам код:

push * *30h ; в десятеричном соответственно 48
push * *3
push * *offset aSum1DSum2D ; "Sum1=%d *** Sum2=%d\n"
call * *sub_401014 ; это типа printf *


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

Удачи

Отправлено: 12:20, 25-09-2003 | #4


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Тут дело в том, что порядок выполнения операций между точками следования не определён. Из фака su.c_cpp:
Цитата:
[pre]>> 036. k[++j] = k[j-- - 1] + k[++j]; Как это считается?
> Q: Отгадай загадку, All. Как будет выглядеть массив k после:
>
>      int k[] = { 0, 1, 2, 3, 4, 5 };
>      int j = 2;
>
>      k[++j] = k[j-- - 1] + k[++j];
>
>    Проверил на трех компиляторах - MSVC++ 6.0 SP3, BC 3.1,
>    Watcom 11.0 - и в C и в C++ режимах. Ответы разные у всех компиляторов!

A: (Serge A. Rider) - 30.10.1999

    Лень глядеть в стандарт, но вот из Страуструпа:
-------------------------------
6.2.2 Evaluation Order
The order of evaluation of subexpressions within an expression is
undefined. In particular, you cannot assume that the expression is
evaluated left to right.
-------------------------------

Короче говоря, в твоем варианте операции ++j, j-- и ++j могут
выполняться в любой последовательности - как захочется компилятору -
со всеми вытекающими. Исключение составляют только ",", && и || - они
всегдя слева направо.

(Hе только эти. Есть еще тернарная операция `?:'. -- Ivan Kosarev (31.10.99))

В общем, перепиши свое выражение, чтобы оно не зависело от порядка
вычисления подвыражений.
[/pre]
Добавлено:

Кстати, так тоже нельзя писать:
Код: Выделить весь код
char buf[] = {1,4,16};
char * p = buf-1;
Т.е. нельзя ничего вычитать из адреса нулевого элемента массива. Это тоже может привести к гипотетическим граблям на некоторых архитектурах. (Например на x86 не в pmode, если у тебя массив лежит в самом начале сегмента, то будут проблемы).

-------
http://ivank.ru


Отправлено: 17:29, 25-09-2003 | #5


Пользователь


Сообщения: 135
Благодарности: 0

Профиль | Отправить PM | Цитировать


Большое спасибо всем.

ivank
_Вам_ отдельный респект за полный и исчерпывающий ответ.

Отправлено: 00:56, 26-09-2003 | #6


Старожил


Сообщения: 167
Благодарности: 0

Профиль | Отправить PM | Цитировать


shurikan
1. Если тебе трудно сказать, то с твоим знанием СИ всё понятно. Я очень даже доходчиво написал, в чём проблема: p=buf-1 - во втором случае складываются не 0-й, 1-й и 2-й элемент
массива, а -1-й, 0-й и 1-й ! А -1-й элемент может быть чем угодно, он не инициализирован.
2. Типы в проге приводятся уже ПОСЛЕ вычисления результата. Напиши такую прогу, например:
unsigned char a=200, b=300;
int c=a+b;
Ты думаешь, что c=500 ?! Сначала вычислится результат с типом char, это 244 (переполнение через байт), а потом уже приведётся к типу int.
unknown bug
Ты немного выше по коду смотреть не пробовал? Это код printf и ВСЁ. Код сложения выше.

Отправлено: 14:22, 27-09-2003 | #7


Аватара для bgg0408

Модер Железа


Сообщения: 1557
Благодарности: 3

Профиль | Сайт | Отправить PM | Цитировать


to Sarge
Я конечно извиняюсь, но проблемы с Си у Вас По тексту видно, что вторая строка (с Sum2) выдает правильный ответ, а первая -нет.
Цитата:
buf[-1]
Ну, и где он там?
Цитата:
6.2.2 Evaluation Order
Вот такое было. Никто не может сказать, что на самом деле суммируется

Насчет кода - правда. Это код вызова функции printf, хотя кто знает, что там компилятор делает, оптимизируя код. Он так извращает код, что иногда оптимизацию приходится выключать

[s]Исправлено: bgg0408, 2:45 28-09-2003[/s]

-------
FreeBSD - forever


Отправлено: 01:40, 28-09-2003 | #8


Пользователь


Сообщения: 135
Благодарности: 0

Профиль | Отправить PM | Цитировать


Sarge Имхо, ты не прав.
Немного перепишем программку, чтоб она соответствовала  Страуструпу.
И введем char *p раньше, для того что-бы buf[] не лежал в начале сегмента на некоторых архитектурах
Код: Выделить весь код
char *p;
char buf[] = {1,4,16};

p= buf-1; 

int Sum2  = *(++p);
    Sum2 += *(++p);
    Sum2 += *(++p);  
Ты серьезно считаешь что это вычисляет  buf[-1]+buf[0]+buf[1] чтоли?

А переполнения в конкретном случае 1+4+16 тоже небыло.

Отправлено: 02:25, 28-09-2003 | #9


Аватара для shurikan

Старожил


Сообщения: 240
Благодарности: 1

Профиль | Отправить PM | Цитировать


Sarge
Неохота флеймить, но...
Цитата:
2. Типы в проге приводятся уже ПОСЛЕ вычисления результата. Напиши такую прогу, например:
unsigned char a=200, b=300;
int c=a+b;
Ты думаешь, что c=500 ?! Сначала вычислится результат с типом char, это 244 (переполнение через байт), а потом уже приведётся к типу int.
Это что такое? Какого типа вообще константы 200 и (особенно) 300? В примере-то вообще был указан тип char, а не unsigned char. Последний имеет своим максимумом значение 255, как ты собираешься запихнуть туда 300? А..., ладно...


Добавлено:

Кстати, вспомни, как вычисляются выражения типа *(++p) и *(p++)...

-------
UNIX, UNAS и др. Myself I'll like 'em


Отправлено: 03:08, 28-09-2003 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Сумма трех байт

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Загрузка трех ОС на одном ПК McLider Хочу все знать 1 10-01-2010 01:59
Загрузка - меню загрузки трех операционных систем с трех HDD sasa74 Microsoft Windows 7 1 13-11-2009 20:34
HDD - Неверная контрольная сумма ATA vzh11 Накопители (SSD, HDD, USB Flash) 4 27-03-2009 17:28
Мd5-сумма Sviaga Хочу все знать 8 28-05-2008 19:41
Байт и Бит Apis.NET Хочу все знать 29 12-01-2002 21:32




 
Переход