![]() |
Небольшая програмка на Си
Сумма трех байт: (Компилировалась на VC6) Код:
char buf[] = {1,4,16}; Цитата:
Цитата:
|
bilytur
Кофе попей, протри глаза, и внимательно посмотри, ЧТО ты складываешь: В первом случае ты складываешь, то что надо - buf[0]+buf[1]+buf[2] (p=buf) Во втором случае buf[-1]+buf[0]+buf[1] (p=buf-1 :o) Так как buf[-1] имеет неопределённое значение, у тебя получаются разные результаты. Добавлено: bilytur Советую также обратить внимание (во избежание другого глюка) на то, что у тебя результат будет CHAR, а не INT, как ты хотел (если ты именно так хотел), возникнет переполнение. Чтобы этого избежать, надо написать int Sum1 = int(*(p++)) + *(p++) + *(p++); |
Sarge
Чё-то у тебя со знанием языка не того... Про постфиксные и префиксные операции слышал чего-нибудь? Сумма char-ов - действительно имеет тип char, н6о это если в арифметическом выражении не присутствуют операнды других типов, тогда будет сделано приведение типов. А здесь приведение производится при присваивании. Вопрос был почему написанное не даёт правильный результат? bilytur Трудно так сразу сказать. Я бы скомпилировал в ассемблер, и посмотрел, чё там VC имеет ввиду, обрабатывая этот текст. Там можно будет понять, когда он указатели продвигает, и на что они в тот момент указывают. Добавлено: А вообще C/C++ не любит таких наворотов. Он проводит оптимизацию при компиляции, а поскольку в выражении все операции равноправны, он может вычислять их в любом порядке, а не слева направо. И, казалось бы, да складывай их в любом порядке, они же одинаковые (операнды, я имею ввиду), но там ещё указатель перемещается, а это он как-то не очень любит. Так что, скомпили в ассемблер... |
Ассемблер рулез :gigi:
Скомпилил твой пример и как оказалось в релизе сложения нет вообще. Вот сам код: push * *30h ; в десятеричном соответственно 48 push * *3 push * *offset aSum1DSum2D ; "Sum1=%d *** Sum2=%d\n" call * *sub_401014 ; это типа printf *:) Как видишь, никакого сложения нет. Компилятор сам вычислил значения Sum1 и Sum2 и заменил их вычисления уже числами... Удачи :biggrin: |
Тут дело в том, что порядок выполнения операций между точками следования не определён. Из фака su.c_cpp:
Цитата:
Кстати, так тоже нельзя писать: Код:
char buf[] = {1,4,16}; |
Большое спасибо всем.
ivank _Вам_ отдельный респект за полный и исчерпывающий ответ. |
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 и ВСЁ. Код сложения выше. |
to Sarge
Я конечно извиняюсь, но проблемы с Си у Вас:) По тексту видно, что вторая строка (с Sum2) выдает правильный ответ, а первая -нет. Цитата:
Цитата:
Насчет кода - правда. Это код вызова функции printf, хотя кто знает:(, что там компилятор делает, оптимизируя код. Он так извращает код, что иногда оптимизацию приходится выключать:( [s]Исправлено: bgg0408, 2:45 28-09-2003[/s] |
Sarge Имхо, ты не прав.
Немного перепишем программку, чтоб она соответствовала Страуструпу. И введем char *p раньше, для того что-бы buf[] не лежал в начале сегмента на некоторых архитектурах Код:
char *p; А переполнения в конкретном случае 1+4+16 тоже небыло. |
Sarge
Неохота флеймить, но... Цитата:
:down: Добавлено: Кстати, вспомни, как вычисляются выражения типа *(++p) и *(p++)... |
Время: 23:41. |
Время: 23:41.
© OSzone.net 2001-