Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Родился
Сообщения: 17
Зарегистрирован: Вт авг 04, 2015 13:52:00

Сообщение dimo41 »

Здравствуйте нe у кого нет этой книги "Программирование графики в Windows 95 М. Янг" очень она бы мне пригодилась , большое спасибо.
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1132
Зарегистрирован: Пт фев 16, 2007 14:18:20
Откуда: Новосибирск

Сообщение Chip115 »

Всем привет!
Требуется в массиве tmp получить строку из четырех символов (цифры).

Код: Выделить всё

uint16_t data = 0012; 
char tmp [4];
sprintf(tmp, "%u", data );
В массиве, при этом,появляется '1' '2' '\0' '\0'.
Как заставить sprintf вывести в массив строку '0012'? Два нуля sprintf интерпретирует как конец строки. А если включить оптимизацию (юзаю IAR), то он еще и символ пробела добавляет.
Теория — это когда все известно, но ничего не работает. Практика — это когда все работает, но никто не знает почему. Мы же объединяем теорию и практику: ничего не работает… и никто не знает почему!
© Альберт Эйнштейн
Контактная информация:
Реклама
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

"%04u" попробуйте. Должен нулями заполнять свободные символы.

Добавлено after 4 minutes 15 seconds:
PS: Совет. Размер массива увеличьте. Должен быть всегда запас под символ окончания строки ('\0').
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Ср сен 13, 2017 05:53:24

Сообщение fulky »

Здравствуйте, помогите упростить код если это возможно, есть 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;
Реклама
Эиком - электронные компоненты и радиодетали
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Код: Выделить всё

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;}
}
слабое место - я не знаю, сколько там у вас всего вариантов case было... поэтому в моём варианте переменная tmp будет неопределена для всех ваших вариантов, кроме 1 и 2.

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

[uquote="Chip115",url="/forum/viewtopic.php?p=3203433#p3203433"]

Код: Выделить всё

uint16_t data = 0012; 
char tmp [4];
sprintf(tmp, "%u", data );
В массиве, при этом,появляется '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 помещает в буфер три символа - пробел в этой позиции был изначально. Оптимизация просто сменила полжение буфера и там оказался немножко другой "мусор".
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Реклама
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Доброго времени суток. Читаю про хорошие манеры программирования на Си. Один из пунктов: "По возможности используйте do { } while(выражение)". Нигде не могу найти объяснение, чем оно лучше while(выражение) { }.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Пока_без_кота писал(а):По возможности используйте do { } while(выражение)
не берите в голову, если это не про макросы сказано. ничем оно не лучше и не хуже.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Благодарствую.
Встал на лапы
Аватара пользователя
Сообщения: 128
Зарегистрирован: Пн фев 08, 2016 10:57:14

Сообщение smalcom »

Нигде не могу найти объяснение, чем оно лучше while(выражение) { }.
в общем случае "while(){}" использует дополнительную команду перехода, т.е. медленнее.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

smalcom писал(а):в общем случае "while(){}" использует дополнительную команду перехода
в общем случае - это рядом со сферическим конём в вакууме? в общем случае как раз наоборот, между всеми вариантами циклов while, for и do нет никакой разницы, а вот в частных случаях она может появляться.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Родился
Сообщения: 18
Зарегистрирован: Чт авг 06, 2015 09:38:22
Откуда: Москва

Сообщение Const14 »

Тело цикла 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
Отсюда видно, что наиболее короткий и простой код генерируется для цикла do...while().
Но пользоваться лучше тем, который больше подходит для данного конкретного случая.
Последний раз редактировалось Const14 Пт окт 27, 2017 09:26:15, всего редактировалось 4 раза.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Const14 писал(а):Многие компиляторы
огласите весь список, пожалуйста
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Родился
Сообщения: 18
Зарегистрирован: Чт авг 06, 2015 09:38:22
Откуда: Москва

Сообщение Const14 »

Чтобы огласить весь список, нужно пересмотреть всё множество компиляторов с языка.
Если Вам не понравилось слово "Многие", то можете заменить его на "Некоторые".
Но, на мой взгляд, сути это не меняет, в общем случае организация цикла do while() и результирующий код для него являются самыми простыми.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Ну во всяком случае AVR-GCC 5.2.1 в ваш список не входит...

Код: Выделить всё

#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);
}
в вышеприведенном тесте проводилась компиляция с оптимизацией -Os, при этом 2 из трех вариантов циклов, делающих одно и то же, заремаривались.

таким образом, на целых 2 байта хуже показал себя цикл while, а остальные два оказались равными.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

Const14 писал(а):Но пользоваться лучше тем, который больше подходит для данного конкретного случая
Не "лучше", а "необходимо" !
Нужно понимать разницу между

Код: Выделить всё

do{}while();
,

Код: Выделить всё

while(){}
и

Код: Выделить всё

for(;;){}
Каждый вариант подходит для конкретного случая. Они не всегда взаимозаменяемы.
Родился
Сообщения: 18
Зарегистрирован: Чт авг 06, 2015 09:38:22
Откуда: Москва

Сообщение Const14 »

ARV
Вы привели частный пример задачи, решаемой с помощью трёх типов цикла, я расписал общий случай.
Естественно, что в результате оптимизации таких простых циклов, генерируемый код имеет одинаковый размер.
Противоречий не вижу. И оспаривать этот пример я, конечно, не буду.

Alex, какой из трёх вариантов, приведённых в примере ARV, Вы считаете "необходимо" использовать?
Спрашиваю потому, что когда писал, то думал, что написать: "следует" или "лучше".
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

Отцы основатели (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.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Const14 писал(а):вы привели частный пример задачи, решаемой с помощью трёх типов цикла, я расписал общий случай.
ну приведите аналогичный тест частного случая, подтверждающего ваше утверждение - в чем проблема?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Родился
Сообщения: 18
Зарегистрирован: Чт авг 06, 2015 09:38:22
Откуда: Москва

Сообщение Const14 »

Собственно, я вообще проблемы не вижу и не могу понять, в чём Вы её видите.
Если мы возьмём пример:
Спойлер

Код: Выделить всё

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();

}
и прокомпилируем "классикой" BC 3.1, то получим:
Спойлер

Код: Выделить всё

   ;	
   ;	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
и увидим, во втором и третьем случае те самые переходы на проверку условия "jmp short @2@86" и "jmp short @3@114"

Теперь прокомпилируем тоже самое компилятором 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
Здесь тоже во втором и третьем случае видим дополнительные переходы "jnc 00104$" и "jnc 00105$" с единственным отличием - проверку условия компилятор размещает перед, а не после тела цикла.
Последний раз редактировалось Const14 Пт окт 27, 2017 15:17:15, всего редактировалось 1 раз.
Ответить

Вернуться в «Разные вопросы по МК»