Вопросы по С/С++ (СИ)
- Сообщения: 17
- Зарегистрирован: Вт авг 04, 2015 13:52:00
Здравствуйте нe у кого нет этой книги "Программирование графики в Windows 95 М. Янг" очень она бы мне пригодилась , большое спасибо.
- Реклама
Всем привет!
Требуется в массиве tmp получить строку из четырех символов (цифры).
В массиве, при этом,появляется '1' '2' '\0' '\0'.
Как заставить sprintf вывести в массив строку '0012'? Два нуля sprintf интерпретирует как конец строки. А если включить оптимизацию (юзаю IAR), то он еще и символ пробела добавляет.
Требуется в массиве tmp получить строку из четырех символов (цифры).
Код: Выделить всё
uint16_t data = 0012;
char tmp [4];
sprintf(tmp, "%u", data );
Как заставить sprintf вывести в массив строку '0012'? Два нуля sprintf интерпретирует как конец строки. А если включить оптимизацию (юзаю IAR), то он еще и символ пробела добавляет.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
© Альберт Эйнштейн
"%04u" попробуйте. Должен нулями заполнять свободные символы.
Добавлено after 4 minutes 15 seconds:
PS: Совет. Размер массива увеличьте. Должен быть всегда запас под символ окончания строки ('\0').
Добавлено after 4 minutes 15 seconds:
PS: Совет. Размер массива увеличьте. Должен быть всегда запас под символ окончания строки ('\0').
- Сообщения: 31
- Зарегистрирован: Ср сен 13, 2017 05:53:24
Здравствуйте, помогите упростить код если это возможно, есть 2 кейса практически идентичных, в первом кейсе выключает затем включает пин МК, во втором наоборот включает а затем выключает, можно ли это собрать как то в функцию при этом уменьшив объем занимаемого кода :
Код: Выделить всё
case 1:
if (flag==0){
PORTB &=~(1<<PB1);
if (tic>=Timer1){flag++; tic= 0;}
}
else {
PORTB |= (1<<PB1);
if (tic>=Timer2){tic = 0; flag=0;}
}
break;
case 2:
if (flag==0){
PORTB |= (1<<PB1);
if (tic>=Timer1){flag++; tic= 0;}
}
else {
PORTB &=~(1<<PB1);
if (tic>=Timer2){tic = 0; flag=0;}
}
break;Код: Выделить всё
char tmp;
switch(???){
case 1: tmp = flag; break;
case 2: tmp = !flag; break;
}
if (tmp==0){
PORTB &=~(1<<PB1);
if (tic>=Timer1){flag++; tic= 0;}
} else {
PORTB |= (1<<PB1);
if (tic>=Timer2){tic = 0; flag=0;}
}скорее всего оптимизация вашего кода должна быть глубже, чем только этот кусочек
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Реклама
- Сообщения: 353
- Зарегистрирован: Вс янв 19, 2014 22:41:55
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]
В массиве, при этом,появляется '1' '2' '\0' '\0'.[/uquote]
На самом деле 0012 это восьмеричная константа (поскольку нолик в начале) а не десятичная - и этот код заполнит буфер тремя символами '1', '0', '\0'.
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]Как заставить sprintf вывести в массив строку '0012'?[/uquote]
Про %04u вам уже сказали, но при этом нужно либо размер tmp увеличить до 5 - поскольку терминатору место нужно. Или использовать snprintf, контролирующий "берега" приёмного буфера. Ну и написать либо data = 12 либо data = 014.
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]Два нуля sprintf интерпретирует как конец строки.[/uquote]
К тому моменту когда sprintf получает data параметром - тех "нулей" и след простыл. И 012 и 0012 и 000012 все равны 10 (decimal).
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]А если включить оптимизацию (юзаю IAR), то он еще и символ пробела добавляет.[/uquote]
Как уже сказано выше sprintf помещает в буфер три символа - пробел в этой позиции был изначально. Оптимизация просто сменила полжение буфера и там оказался немножко другой "мусор".
Код: Выделить всё
uint16_t data = 0012;
char tmp [4];
sprintf(tmp, "%u", data );
На самом деле 0012 это восьмеричная константа (поскольку нолик в начале) а не десятичная - и этот код заполнит буфер тремя символами '1', '0', '\0'.
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]Как заставить sprintf вывести в массив строку '0012'?[/uquote]
Про %04u вам уже сказали, но при этом нужно либо размер tmp увеличить до 5 - поскольку терминатору место нужно. Или использовать snprintf, контролирующий "берега" приёмного буфера. Ну и написать либо data = 12 либо data = 014.
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]Два нуля sprintf интерпретирует как конец строки.[/uquote]
К тому моменту когда sprintf получает data параметром - тех "нулей" и след простыл. И 012 и 0012 и 000012 все равны 10 (decimal).
[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]А если включить оптимизацию (юзаю IAR), то он еще и символ пробела добавляет.[/uquote]
Как уже сказано выше sprintf помещает в буфер три символа - пробел в этой позиции был изначально. Оптимизация просто сменила полжение буфера и там оказался немножко другой "мусор".
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
- Сообщения: 359
- Зарегистрирован: Чт авг 08, 2013 01:06:54
Доброго времени суток. Читаю про хорошие манеры программирования на Си. Один из пунктов: "По возможности используйте do { } while(выражение)". Нигде не могу найти объяснение, чем оно лучше while(выражение) { }.
не берите в голову, если это не про макросы сказано. ничем оно не лучше и не хуже.Пока_без_кота писал(а):По возможности используйте do { } while(выражение)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 359
- Зарегистрирован: Чт авг 08, 2013 01:06:54
- Сообщения: 128
- Зарегистрирован: Пн фев 08, 2016 10:57:14
в общем случае "while(){}" использует дополнительную команду перехода, т.е. медленнее.Нигде не могу найти объяснение, чем оно лучше while(выражение) { }.
в общем случае - это рядом со сферическим конём в вакууме? в общем случае как раз наоборот, между всеми вариантами циклов while, for и do нет никакой разницы, а вот в частных случаях она может появляться.smalcom писал(а):в общем случае "while(){}" использует дополнительную команду перехода
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Тело цикла do ... while() выполняется по крайней мере один раз.
Многие компиляторы код проверки условия и переход на начало тела цикла располагают после тела цикла. Код, генерируемый для циклов for(){} и while() {} отличается тем, что для обеспечения проверки условия перед первой итерацией цикла, генерируется команда перехода на проверку условия.
То есть для цикла
генерируется:
Для цикла
генерируется:
Для цикла
генерируется:
Отсюда видно, что наиболее короткий и простой код генерируется для цикла do...while().
Но пользоваться лучше тем, который больше подходит для данного конкретного случая.
Многие компиляторы код проверки условия и переход на начало тела цикла располагают после тела цикла. Код, генерируемый для циклов for(){} и while() {} отличается тем, что для обеспечения проверки условия перед первой итерацией цикла, генерируется команда перехода на проверку условия.
То есть для цикла
Код: Выделить всё
do
<body>
while(<e1>)
Код: Выделить всё
L1:
<body>
if( <e1> ) goto L1
Код: Выделить всё
while( <e1> )
{
<body>
}
Код: Выделить всё
goto Ltest;
L1:
<body>
Ltest:
if( <e1> ) goto L1
Код: Выделить всё
for(<e2>; <e1>; <e3> )
{
<body>
}
Код: Выделить всё
<e2>
goto Ltest;
L1:
<body>
<e3>
Ltest:
if( <e1> ) goto L1
Но пользоваться лучше тем, который больше подходит для данного конкретного случая.
Последний раз редактировалось Const14 Пт окт 27, 2017 09:26:15, всего редактировалось 4 раза.
огласите весь список, пожалуйстаConst14 писал(а):Многие компиляторы
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Чтобы огласить весь список, нужно пересмотреть всё множество компиляторов с языка.
Если Вам не понравилось слово "Многие", то можете заменить его на "Некоторые".
Но, на мой взгляд, сути это не меняет, в общем случае организация цикла do while() и результирующий код для него являются самыми простыми.
Если Вам не понравилось слово "Многие", то можете заменить его на "Некоторые".
Но, на мой взгляд, сути это не меняет, в общем случае организация цикла do while() и результирующий код для него являются самыми простыми.
Ну во всяком случае AVR-GCC 5.2.1 в ваш список не входит...в вышеприведенном тесте проводилась компиляция с оптимизацией -Os, при этом 2 из трех вариантов циклов, делающих одно и то же, заремаривались.
таким образом, на целых 2 байта хуже показал себя цикл while, а остальные два оказались равными.
Код: Выделить всё
#include <avr/io.h>
int main(void){
uint8_t i;
// вариант 1 - 106 байт flash
i = 12;
while(i--){
PORTB = PINC;
}
// вариант 2 - 104 байта flash
for(i = 12; i; i--){
PORTB = PORTC;
}
// вариант 3 - 104 байта flash
i = 12;
do{
PORTB = PORTC;
i--;
} while(i);
}таким образом, на целых 2 байта хуже показал себя цикл while, а остальные два оказались равными.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Не "лучше", а "необходимо" !Const14 писал(а):Но пользоваться лучше тем, который больше подходит для данного конкретного случая
Нужно понимать разницу между
Код: Выделить всё
do{}while();
Код: Выделить всё
while(){}
Код: Выделить всё
for(;;){}
ARV
Вы привели частный пример задачи, решаемой с помощью трёх типов цикла, я расписал общий случай.
Естественно, что в результате оптимизации таких простых циклов, генерируемый код имеет одинаковый размер.
Противоречий не вижу. И оспаривать этот пример я, конечно, не буду.
Alex, какой из трёх вариантов, приведённых в примере ARV, Вы считаете "необходимо" использовать?
Спрашиваю потому, что когда писал, то думал, что написать: "следует" или "лучше".
Вы привели частный пример задачи, решаемой с помощью трёх типов цикла, я расписал общий случай.
Естественно, что в результате оптимизации таких простых циклов, генерируемый код имеет одинаковый размер.
Противоречий не вижу. И оспаривать этот пример я, конечно, не буду.
Alex, какой из трёх вариантов, приведённых в примере ARV, Вы считаете "необходимо" использовать?
Спрашиваю потому, что когда писал, то думал, что написать: "следует" или "лучше".
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Отцы основатели (K&R) пишут:
циклы while и for обладают тем приятным свойством, что в них проверка окончания осуществляется в начале, а не в конце цикла. Третий оператор цикла языка C, do-while, проверяет условие окончания в конце, после каждого прохода через тело цикла; тело цикла всегда выполняется по крайней мере один раз.
Как и можно было ожидать, цикл do-while используется значительно реже, чем while и for, составляя примерно пять процентов от всех циклов. Тем не менее, иногда он оказывается полезным, как, например, в следующей функции itoa, которая преобразует число в символьную строку (обратная функции atoi). Эта задача оказывается несколько более сложной, чем может показаться сначала. Дело в том, что простые методы выделения цифр генерируют их в неправильном порядке. Мы предпочли получить строку в обратном порядке, а затем обратить ее.
Код: Выделить всё
/* конвертировать n в строку s */
itoa(n, s)
char s[];
int n;
{
int i, sign;
if((sign = n) < 0) /* сохранить знак */
n = -n; /* сделать n положительным */
i = 0;
do { /* генерируем цифры в обратном порядке */
s[i++] = n % 10 + '0'; /* получить следующую цифру */
} while((n /= 10) > 0); /* удалить ее */
if(sign < 0)
s[i++] = '-'
s[i] = '\0';
reverse(s);
}Цикл do-while здесь необходим, или по крайней мере удобен, поскольку, каково бы ни было значение n, массив s должен содержать хотя бы один символ. Мы заключили в фигурные скобки один оператор, составляющий тело do-while, хотя это и не обязательно, для того, чтобы торопливый читатель не принял часть while за начало оператора цикла while.
ну приведите аналогичный тест частного случая, подтверждающего ваше утверждение - в чем проблема?Const14 писал(а):вы привели частный пример задачи, решаемой с помощью трёх типов цикла, я расписал общий случай.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Собственно, я вообще проблемы не вижу и не могу понять, в чём Вы её видите.
Если мы возьмём пример:
и прокомпилируем "классикой" BC 3.1, то получим:
и увидим, во втором и третьем случае те самые переходы на проверку условия "jmp short @2@86" и "jmp short @3@114"
Теперь прокомпилируем тоже самое компилятором SDCC под "процессор" 8051 и получим код:
Здесь тоже во втором и третьем случае видим дополнительные переходы "jnc 00104$" и "jnc 00105$" с единственным отличием - проверку условия компилятор размещает перед, а не после тела цикла.
Если мы возьмём пример:
Спойлер
Код: Выделить всё
unsigned char a,b,c;
//----------------------
void f1(void)
{
c = 0;
do
{
c += b;
b++;
}while( a>b );
}
void f2(void)
{
c=0;
while( a>b )
{
c += b;
b++;
}
}
void f3(void)
{
for( c=0; a>b; b++ )
{
c += b;
}
}
//----------------------
void main(void)
{
a = 10;
b = 2;
f1();
//---------
a = 10;
b = 2;
f2();
//---------
a = 10;
b = 2;
f3();
}
Спойлер
Код: Выделить всё
;
; void f1(void)
;
assume cs:_TEXT
_f1 proc near
push bp
mov bp,sp
;
; {
; c = 0;
;
mov byte ptr DGROUP:_c,0
@1@58:
;
; do
; {
; c += b;
;
mov al,byte ptr DGROUP:_b
add byte ptr DGROUP:_c,al
;
; b++;
;
inc byte ptr DGROUP:_b
;
; }while( a>b );
;
mov al,byte ptr DGROUP:_a
cmp al,byte ptr DGROUP:_b
ja short @1@58
;
; }
;
pop bp
ret
_f1 endp
;
; void f2(void)
;
assume cs:_TEXT
_f2 proc near
push bp
mov bp,sp
;
; {
; c=0;
;
mov byte ptr DGROUP:_c,0
jmp short @2@86
@2@58:
;
; while( a>b )
; {
; c += b;
;
mov al,byte ptr DGROUP:_b
add byte ptr DGROUP:_c,al
;
; b++;
;
inc byte ptr DGROUP:_b
@2@86:
mov al,byte ptr DGROUP:_a
cmp al,byte ptr DGROUP:_b
ja short @2@58
;
; }
; }
;
pop bp
ret
_f2 endp
;
; void f3(void)
;
assume cs:_TEXT
_f3 proc near
push bp
mov bp,sp
;
; {
; for( c=0; a>b; b++ )
;
mov byte ptr DGROUP:_c,0
jmp short @3@114
@3@58:
;
; {
; c += b;
;
mov al,byte ptr DGROUP:_b
add byte ptr DGROUP:_c,al
inc byte ptr DGROUP:_b
@3@114:
mov al,byte ptr DGROUP:_a
cmp al,byte ptr DGROUP:_b
ja short @3@58
;
; }
; }
;
pop bp
ret
_f3 endp
Теперь прокомпилируем тоже самое компилятором SDCC под "процессор" 8051 и получим код:
Спойлер
Код: Выделить всё
;------------------------------------------------------------
;Allocation info for local variables in function 'f1'
;------------------------------------------------------------
; 8051test.c:6: void f1(void)
; -----------------------------------------
; function f1
; -----------------------------------------
_f1:
ar7 = 0x07
ar6 = 0x06
ar5 = 0x05
ar4 = 0x04
ar3 = 0x03
ar2 = 0x02
ar1 = 0x01
ar0 = 0x00
; 8051test.c:8: c = 0;
mov _c,#0x00
; 8051test.c:9: do
00101$:
; 8051test.c:11: c += b;
mov a,_b
add a,_c
mov _c,a
; 8051test.c:12: b++;
inc _b
; 8051test.c:13: }while( a>b );
clr c
mov a,_b
subb a,_a
jc 00101$
ret
;------------------------------------------------------------
;Allocation info for local variables in function 'f2'
;------------------------------------------------------------
; 8051test.c:16: void f2(void)
; -----------------------------------------
; function f2
; -----------------------------------------
_f2:
; 8051test.c:18: c=0;
mov _c,#0x00
; 8051test.c:19: while( a>b )
00101$:
clr c
mov a,_b
subb a,_a
jnc 00104$
; 8051test.c:21: c += b;
mov a,_b
add a,_c
mov _c,a
; 8051test.c:22: b++;
inc _b
sjmp 00101$
00104$:
ret
;------------------------------------------------------------
;Allocation info for local variables in function 'f3'
;------------------------------------------------------------
; 8051test.c:26: void f3(void)
; -----------------------------------------
; function f3
; -----------------------------------------
_f3:
; 8051test.c:28: for( c=0; a>b; b++ )
mov _c,#0x00
00103$:
clr c
mov a,_b
subb a,_a
jnc 00105$
; 8051test.c:30: c += b;
mov a,_b
add a,_c
mov _c,a
; 8051test.c:28: for( c=0; a>b; b++ )
inc _b
sjmp 00103$
00105$:
ret
Последний раз редактировалось Const14 Пт окт 27, 2017 15:17:15, всего редактировалось 1 раз.


