newbie needs tissues for character array issues

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I need to provide a contiguous memory space for my function to write to. How do I do that?
I.e.: "s" only points to a single byte, and I need a truckload, but I don't know much much. I don't get to use 'new', but I think I can use malloc with ...

Here's the function call:

int main()
{
	init_usart(38400);
	char *s = NULL;
	txstr("\rusart-test2\n\rType!\n\n\r");

	while(1)
	{
		s = rxstr_ESC(130,s);
		txstr("\n\r...\n\r");
	}
}

Here's the relevant header:

struct index
{
	uint8_t col;
	uint8_t row;
};

void init_usart(uint32_t baudrate);
void tx(char c);
char rx();
void txstr(const char *s);
char *rxstr_ESC(uint8_t max, char *s);
void echo(char c);

Here's the function definition:

// gets characters until escape key
char *rxstr_ESC(uint8_t max, char *s)
{
	index i; i.col = 0; i.row = 0;
	uint16_t n = 0;

	while ((s[n] != '\e') && (n=2)
					i.col -= 2;
				else
					i.col = 0;
				break;
			case '\t':
				if (i.col<55)
				{
					i.col += 2;
					txstr("  ");
				}
				else
				{
					while (++i.col<59)
						tx(' ');
				}
				break;
			case '\n':
			case '\r':
				i.col = 2;
				txstr("  ");
				break;
			default:
				break;
		}
		i.col++;
	}
	ledmsg("---");
	return s;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I.e.: "s" only points to a single byte

No, it points to memory space 0 (which will certainly be the memory space of some other variable).
Quote:
but I think I can use malloc with ...

You could, but I wouldn't.
Quote:
but I don't know much much.

But you are specifying a max of 130 in your call to rxstr_ESC(), so make an array of that size:

char s[130];
s[0] = 0; // Start with a null string

But you would not want (or need) to return s from rxstr_ESC().

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So..

char s[130];
s[0] = 0;
char *p = s;

p = rxstr_ESC(130,p);

omg it works! 8)

Thanks Koshchi! I'll clean it up.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Again, you don't need rxstr_ESC to return a value. You can just do:

char s[130];
s[0] = 0;

rxstr_ESC(130, s);

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was copying a style from the avr-libc::string library:

char * strcpy ( char * 	dest,					// example
					const char * 	src	 
					)

I've heard rumours about the compiler allocating registers for that variable (char * dest) even though it was passed to it by reference (it would normally be restricted to the stack) because it is being returned, but I won't pretend to know what these rumours are based on.

Also, s is not *p... Would have to change the function definition, which I may just do. :P

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I've heard rumours about the compiler allocating registers for that variable (char * dest) even though it was passed to it by reference (it would normally be restricted to the stack) because it is being returned, but I won't pretend to know what these rumours are based on.

Scotch mist?

The source for strcpy() in AVR-LibC:

#define dest_hi r25
#define dest_lo r24
#define src_hi r23
#define src_lo r22

; 9 words, (14 + strlen(src) * 7) cycles

	ASSEMBLY_CLIB_SECTION
	.global	_U(strcpy)
	.type	_U(strcpy), @function
_U(strcpy):
	X_movw	ZL, src_lo
	X_movw	XL, dest_lo
.L_strcpy_loop:
	ld	__tmp_reg__, Z+
	st	X+, __tmp_reg__
	tst	__tmp_reg__
	brne	.L_strcpy_loop
; return dest (unchanged)
	ret
.L_strcpy_end:

'dest' comes in R25:R24 (as per the ABI) and leaves the same way, nothing ever changes it - X is the incremented copy of 'dest'

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Also, s is not *p... Would have to change the function definition

No you wouldn't. These two statements are equivalent:

rxstr_ESC(130, s);
rxstr_ESC(130, &(s[0]));

And besides, don't you in your routine use s[n] even though s is defined as char *s, not char s[]?

Quote:
I've heard rumours about the compiler allocating registers for that variable (char * dest) even though it was passed to it by reference (it would normally be restricted to the stack) because it is being returned

Whether the compiler uses registers or the stack depends on what the compiler thinks is more efficient. There is nothing that will "restrict it to stack" unless there are not enough registers available. But with your use of s being so inefficient, the compiler may have a hard time in optimizing anyways.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
'dest' comes in R25:R24 (as per the ABI) and leaves the same way, nothing ever changes it - X is the incremented copy of 'dest'
Yes.. now I wonder if this would assemble differently:
void strcpy (char *, const char *)

I'll have to check in a few weeks, when my calendar isn't attacking me.

As Koschi mentioned, my code isn't particularly efficient, so any small optimizations by the compiler will go unnoticed. I am new to programming, and am trying to pick up good habits; a well-optimized library like avr-libc seems like a good place to do so.
The original intent of this function was to treat the input char* in a way similar to a stack (but I would parse it FIFO). Assuming the function itself was genius-fast, what is a better way to pass my variables around, in this case? 'Suppose 'char s[]' would be more straightforward, but then I don't think I can change its length.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

now I wonder if this would assemble differently:
Code:
void strcpy (char *, const char *)
I'll have to check in a few weeks,

But the ABI is fully documented in the AVR-LibC FAQ - there's no mystery about it. See FAQ#13:

http://www.nongnu.org/avr-libc/u...