|
|
  |
Деление int на size_t |
|
|
|
Nov 7 2013, 09:37
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(AHTOXA @ Nov 7 2013, 13:30)  1. sizeof() возвращает size_t, независимо от значения. 2. int/size_t возвращает size_t. (при условии sizeof(int) == sizeof(size_t) ) Это требование стандарта. Вы считаете, что несоблюдение компилятором стандарта языка говорит о том, что этот компилятор "более продвинутый"?  Кстати, есть вариант, что в этих продвинутых компиляторах int просто длиннее, чем size_t, и поэтому всё получается нормально без нарушения стандарта. А что, Вы будете спорить, что IAR и прочие коммерческие компилеры - более продвинутые? Это видно и на моём примере  А в защиту GCC можно сказать только - что он "блюдёт" стандарты.
|
|
|
|
|
Nov 7 2013, 12:27
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(AHTOXA @ Nov 7 2013, 15:17)  Вот уж не ожидал, что приведённое мной объяснение может вызвать такую реакцию. Подумайте ещё вот о чём. Существует ненулевая вероятность, что в какой-то из следующих версий IAR данное несоответствие стандарту устранят...  Да обычная реакция. Когда в очередной раз слышишь, что маразм из разряда -2/1=2 - это стандарт. Не только IAR "игнорирует" ваш стандарт, но и CodeVisionAVR. Я еще Keil не проверял, возможно, он тоже из разряда "недоделанных"  Может быть, отличия в результатах компиляции - вовсе не различная трактовка стандартов, а работа оптимизации?
|
|
|
|
|
Nov 7 2013, 16:33
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Это не мой стандарт, это стандарт языка Си. И лучше такой стандарт, чем никакого. Странно, что вы, вроде бы достаточно опытный разработчик, этого не понимаете. А уж ссылки на CodeVisionAVR - это вообще нонсенс, поскольку давно известно, что CodeVisionAVR - это компилятор "языка, похожего на Си":) Вы лучше проверьте "взрослые" компиляторы. (И посмотрите в IAR, чему там равны sizeof(int) и sizeof(size_t), вдруг и IAR соблюдает стандарт).
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 7 2013, 21:31
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(AHTOXA @ Nov 7 2013, 20:33)  (И посмотрите в IAR, чему там равны sizeof(int) и sizeof(size_t), вдруг и IAR соблюдает стандарт). Оба равны двум, что неудивительно. Только у одного 2+2 равно 4, а у второго - 5. Думаете, какой из них больше соблюдает стандарт? ЗЫ: сейчас докачаю Кейл и проверю там, на АРМ. ЗЗЫ: Упс, обновил AtmelStudio на последнюю версию 6.1 (стояла 6.0), ничего в тексте не менял, пересобрал проект - появилось знаковое деление и обработка отрицательных значений. То есть исправили багу и теперь поведение GCC стало аналогичным IAR. Попробуйте теперь объяснить, как необходимо правильно трактовать разные умные стандарты Ставить Кейл пока не стану, уверен, что его код будет аналогичен IAR.
|
|
|
|
|
Nov 8 2013, 04:17
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(sonycman @ Nov 8 2013, 03:31)  Оба равны двум, что неудивительно. Да всяко бывает. Бывает 4 (на АРМ-ах). Бывает и 8 (на 64-битных системах). Ещё бывает, что размер int и size_t разный. Цитата(sonycman @ Nov 8 2013, 03:31)  Только у одного 2+2 равно 4, а у второго - 5. Думаете, какой из них больше соблюдает стандарт? Больше соблюдает тот, у которого результат соответствует стандарту. Если по стандарту должно получиться 5, то второй  Цитата(sonycman @ Nov 8 2013, 03:31)  ЗЗЫ: Упс, обновил AtmelStudio на последнюю версию 6.1 (стояла 6.0), ничего в тексте не менял, пересобрал проект - появилось знаковое деление и обработка отрицательных значений. То есть исправили багу и теперь поведение GCC стало аналогичным IAR. Попробуйте теперь объяснить, как необходимо правильно трактовать разные умные стандарты  Очень рад за вас  Не знаю, почему так. Возможно, здесь константа вычисляется во время компиляции, и поэтому она трактуется как нетипизированная. Для интереса попробуйте написать функцию, которая возвращает size_t, и поделить int на результат этой функции.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 8 2013, 10:19
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Прошу прощения, поторопился я вчера с выводами, поздно было, допустил невнимательность и рано обрадовался  Не заметил приведение типов - нет, версия студии 6.1 всё так же остаётся верна стандартам и сама себе - знак так же отбрасывается, как и раньше. Зато потестил Кейл - как и предполагал, работает по аналогии с IAR - чихает на стандарты, делит со знаком и его дальнейшей обработкой. Наш человек  Подставлял в IAR вместо sizeof() переменную с типом size_t - без разницы, никакого превращения Int в беззнаковый тип не происходит, всё работает как и раньше.
|
|
|
|
|
Nov 8 2013, 13:39
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Цитата(sonycman @ Nov 8 2013, 18:02)  Вы про IAR? Уточните, пожалуйста. Смогу предоставить ассемлерный листинг только ночью или завтра, к сожалению. Честно говоря, я не думал про какой-то конкретный компилятор. Я под Линем сижу, могу притащить сюда листин от gcc. (Если кто-нибудь меня не опередит к этому времени, гы-гы!) Давайте какой-нибудь простенький код обуликуем, откомпилируем и сравним. Внимание нужно будет уделить именно арифметическим командам проца, которые как раз занимаются вычислением деления int на size_t. Ну что, попробуем сделать?
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 9 2013, 19:56
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Несколько устав уже от нюансов по поводу интерпретации стандатров различными компиляторами, нашёл всё таки время "добить" код, прогнав его через IAR и Keil. Результаты не совсем однозначные, но вот они, какие есть. Исходный код: Код volatile int tbuf[20], result; while (1) { int t = 0; for (unsigned char c = 0; c < sizeof(tbuf)/sizeof(int); c++) { t += tbuf[c]; } t /= sizeof(tbuf)/sizeof(int); //деление INT на SIZE_T, приводящее к "тихой" ошибке result = t < 0 ? t/5 : t;
} Генерируется он на всех трёх компиляторах тихо, без ошибок и предупреждений, хотя несёт в себе ошибку, превращающую INT при делении в беззнаковый тип, отбрасывая таким образом все отрицательные значения. При этом GCC полностью удаляет из полученного кода часть, которая обрабатывает отрицательный результат. В IAR и Keil она присутствует, хотя выполнена может быть далеко не всегда. Полученный код на GCC (Atmel Studio 6.1): CODE 6a: 60 e0 ldi r22, 0x00 ; 0 6c: 70 e0 ldi r23, 0x00 ; 0 6e: 80 e0 ldi r24, 0x00 ; 0 70: 90 e0 ldi r25, 0x00 ; 0 72: fb 01 movw r30, r22 74: ee 0f add r30, r30 76: ff 1f adc r31, r31 78: 21 e0 ldi r18, 0x01 ; 1 7a: 30 e0 ldi r19, 0x00 ; 0 7c: 2c 0f add r18, r28 7e: 3d 1f adc r19, r29 80: e2 0f add r30, r18 82: f3 1f adc r31, r19 84: 20 81 ld r18, Z 86: 31 81 ldd r19, Z+1 ; 0x01 88: 82 0f add r24, r18 8a: 93 1f adc r25, r19 8c: 6f 5f subi r22, 0xFF ; 255 8e: 7f 4f sbci r23, 0xFF ; 255 90: 64 31 cpi r22, 0x14 ; 20 92: 71 05 cpc r23, r1 94: 71 f7 brne .-36 ; 0x72 <main+0x1c> 96: 03 d0 rcall .+6 ; 0x9e <__udivmodhi4> 98: 7a a7 std Y+42, r23 ; 0x2a 9a: 69 a7 std Y+41, r22 ; 0x29 9c: e6 cf rjmp .-52 ; 0x6a <main+0x14>
Код IAR (v6.21): CODE \ ??main_1: \ 00000004 E045 LDI R20, 5 \ 00000006 E050 LDI R21, 0 \ 00000008 .... RCALL ?SS_DIVMOD_L02 \ ??main_2: \ 0000000A 8308 ST Y, R16 \ 0000000C 8319 STD Y+1, R17 \ ??main_0: \ 0000000E E000 LDI R16, 0 \ 00000010 E010 LDI R17, 0 \ 00000012 E020 LDI R18, 0 \ ??main_3: \ 00000014 2FEC MOV R30, R28 \ 00000016 5FEE SUBI R30, 254 \ 00000018 2F32 MOV R19, R18 \ 0000001A 0F33 LSL R19 \ 0000001C 0FE3 ADD R30, R19 \ 0000001E 8140 LD R20, Z \ 00000020 8151 LDD R21, Z+1 \ 00000022 0F04 ADD R16, R20 \ 00000024 1F15 ADC R17, R21 \ 00000026 9523 INC R18 \ 00000028 3124 CPI R18, 20 \ 0000002A F3A0 BRCS ??main_3 \ 0000002C E144 LDI R20, 20 \ 0000002E E050 LDI R21, 0 \ 00000030 .... RCALL ?SS_DIVMOD_L02 \ 00000032 2311 TST R17 \ 00000034 F33A BRMI ??main_1 \ 00000036 CFE9 RJMP ??main_2
Здесь уже ошибки нет, применяется деление со знаком. Однако, если скомпилировать не Release код, а Debug, при тех же настройках оптимизации, получается код с беззнаковым делением. Интересно Кейл (uVision v4.72) тоже применяет деление без знака, как и GCC, хотя мне вначале казалось наоборот. Прошу простить за невнимательность  Код 00000c 2314 MOVS r3,#0x14 00000e 466a MOV r2,sp ;33 ;;;37 ;;;38 result = t < 0 ? t/5 : t; 000010 2405 MOVS r4,#5 |L1.18| 000012 2100 MOVS r1,#0 ;30 000014 ea4f0001 MOV.W r0,r1 ;31 |L1.24| 000018 f8525020 LDR r5,[r2,r0,LSL #2] ;33 00001c 1c40 ADDS r0,r0,#1 ;31 00001e 4429 ADD r1,r1,r5 ;33 000020 2814 CMP r0,#0x14 ;31 000022 d3f9 BCC |L1.24| 000024 fbb1f0f3 UDIV r0,r1,r3 ;36 000028 2800 CMP r0,#0 00002a da01 BGE |L1.48| 00002c fb90f0f4 SDIV r0,r0,r4 |L1.48| ;;;39 ;;;40 } 000030 9014 STR r0,[sp,#0x50] 000032 e7ee B |L1.18| Логика несколько неясна, после UDIV проверять значение на отрицательный знак? Это возможно разве? Но не перестаю восхищаться красивым, мощным, ёмким и компактным кодом Cortex ARM. Он в два раза короче, чем код для AVR!
|
|
|
|
|
Nov 28 2013, 20:35
|
Местный
  
Группа: Участник
Сообщений: 313
Регистрация: 2-07-11
Пользователь №: 66 023

|
Цитата(sonycman @ Nov 9 2013, 22:56)  При этом GCC полностью удаляет из полученного кода часть, которая обрабатывает отрицательный результат. Чудеса оптимизации. Умеет определять, что после деления 0...65535 на 20 получится 0...3276, после преобразования к знаковому будет не отрицательным у ветка для t<0 не нужна. Цитата(sonycman @ Nov 9 2013, 22:56)  Код IAR (v6.21): ... Здесь уже ошибки нет, применяется деление со знаком. Однако, если скомпилировать не Release код, а Debug, при тех же настройках оптимизации, получается код с беззнаковым делением. Интересно  Увы, IAR не вызывает доверия. Самый худший вариант, когда результат зависит от включения отладки  .
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|