Hi !
I am new to C. I am developing C for an Assembly and C combined code for a project. I need to display simple messages to the Hyper terminal using C.

To be specific, (See attached snippet of code which I am trying to run on Keil toolset) I am trying to declare a global array of characters and process it in one or more functions. Since the Char S[] statement is outside of Main () so it is global. However if I declare it as extern char s[] in the cDispMsg routine, I get an error --> " 's' : invalid class error" . On the other hand, if I comment out the extern char s[] declaration, I get an error -->"subscript on non-array or too many dimensions"
Given all this how can I access the elements of s[] as in the statements below (see attached file). send them to display or do some processing with them ?
for (i=0; s !='\0';i++)
cSend_Byte (s);
[By the way ignore the code for SBUF etc., it is for an 8051 embedded controller UART.]
So the bottom line is, can anyone tell me what I am doing wrong and how to fix it ?
if there is some standard way to declare a string or structure and have it accessible from a function ? Does this change if the function is in a different file ?

I tried the examples from K&R's classic book on C but they dont' do much with UARTs, just Printf so many examples are not useful.

Attachments
/***********************************************************************
Author			:	Bhal Tulpule
Date			:	26 March 2008
File			:	DEMO1.C 
Version		  	:	LVDT_V2
Hardware      	:	ADuC831 Eval Board
Modification	:	Original LVDT files are compiled.
				:	CPUT_BYTE () routine in assembly, when called worked only on first call.
				:	solution is to write C-only routines for I/O thru SBUF, AND
				:	not change the GET_BYTE, SEND_BYTE assembly routines working thru RX_BYTE etc.
				:	i.e., no sharing of routines. 
				:	UART_INTR will not clear RI, TI. It will be done by Serial I/O routines in C/ASM resp.
************************************************************************/
#pragma  DEBUG OBJECTEXTEND CODE       	/* pragma lines can contain state C51 */
#include <ADuC831.h>                    /* Include ADuC831 header file */
//#include <HT83C51.h>
#include <math.h>
#include <string.h>
//#include <stdio.h>
/*1000h,MAIN_ASSEMBLY (0100h),?C_C51STARTUP(0600h),?C?LIB_CODE(0E00h)*/

/* mux channel defines */
//T2 based on 11.0592Mhz crystal, 0xFF-0xE6 = 26*12/11.0592Mhz=28us

/* Macro definitions */

/* Externals */

extern void BOOTLOADER(void);
void cSend_Byte (unsigned char);
void cGet_Byte ();
void cDispMsg (char);
char s [30];
char s[] = "It is working";
//**********************************
/* Main Loop
;/**********************************/

void main (void)
{
//	extern char s[];
//char s[] = "It is working";
	unsigned char mybyte;
//	int len;
//	int i;
	BOOTLOADER (); 
	
	do 
	{
		cGet_Byte ();
		mybyte = SBUF;
		cSend_Byte (mybyte);
		cSend_Byte (mybyte+1);
		cSend_Byte ('Y');
//		strcpy (s,"It is working");
//		cSend_Byte (strlen(s)); 
//		for (i=0; s[i] !='\0';i++)
//			cSend_Byte (s[i]);
//		cSend_Byte ('\n');
		mybyte = 0x56;	/* = ASCII for V */
		cSend_Byte (mybyte);
		cDispMsg (s);
	} while (1);

}
/*****************************************************************************/
void cDispMsg (char s)
// I wanted this routine to display a message that would be passed in via s; but it does not work;
	extern char s[];
	{
	int i;
//	void extern cSend_Byte (); not necessary as it is in the same file (?)
	for (i=0; s[i] !='\0';i++) //I don't understand why these next 2 line do not work */
		cSend_Byte (s[i]);
	cSend_Byte ('\n');

	return;
	}

/*****************************************************************************/
void cSend_Byte (unsigned char x)
	{
		SBUF=x;
		while (TI==0);			/* TI is not cleared in the UART_INTR */
		TI=0;
	}
/*****************************************************************************/
void cGet_Byte ()
	{
		while (RI == 0);
		RI=0;					/* RI is not cleared in the UART_INTR */
	}

First you need to decide if you want to use parameters to move s around, or access it globally. Right now you're mixing the two together and as a result you have way too many variables named s. This uses parameters rather than the global variable:

#include <stdio.h>

void cSend_Byte ( unsigned char );
void cGet_Byte ( void );
void cDispMsg ( const char * );

char s[] = "It is working";

/*
  JSW (2008-4-1): Added this for debugging without an emulator
*/
static unsigned char SBUF = 0;

void main ( void )
{
  unsigned char mybyte;

  do 
  {
    cGet_Byte();
    mybyte = SBUF;
    cSend_Byte ( mybyte );
    cSend_Byte ( mybyte + 1 );
    cSend_Byte ( 'Y' );
    mybyte = 'V';
    cSend_Byte ( mybyte );
    cDispMsg ( s );
  } while ( 1 );
}

void cDispMsg ( const char *s )
{
  int i;

  for ( i = 0; s[i] !='\0'; i++ )
    cSend_Byte ( s[i] );
  cSend_Byte ( '\n' );

  return;
}

void cSend_Byte ( unsigned char x )
{
  putchar ( x );
}

void cGet_Byte ( void )
{
  SBUF = (unsigned char)getchar();
}

And this uses the global directly:

#include <stdio.h>

void cSend_Byte ( unsigned char );
void cGet_Byte ( void );
void cDispMsg ( void );

char s[] = "It is working";

/*
  JSW (2008-4-1): Added this for debugging without an emulator
*/
static unsigned char SBUF = 0;

void main ( void )
{
  unsigned char mybyte;

  do 
  {
    cGet_Byte();
    mybyte = SBUF;
    cSend_Byte ( mybyte );
    cSend_Byte ( mybyte + 1 );
    cSend_Byte ( 'Y' );
    mybyte = 'V';
    cSend_Byte ( mybyte );
    cDispMsg ( s );
  } while ( 1 );
}

void cDispMsg ( void )
{
  int i;

  // Assuming cDispMsg is in a different
  // file from the definition of s
  extern char s[];

  for ( i = 0; s[i] !='\0'; i++ )
    cSend_Byte ( s[i] );
  cSend_Byte ( '\n' );

  return;
}

void cSend_Byte ( unsigned char x )
{
  putchar ( x );
}

void cGet_Byte ( void )
{
  SBUF = (unsigned char)getchar();
}

Notice that my examples use the "not useful" standard I/O functions. :icon_rolleyes:

Thanks for your help.
I tested solution 1 (passing paramenter s) and it worked !. As for 2nd suggestion, it kind of did not work at first because all routines were in the same file. However when I splt cDispMsg into a seperate file, it did not work as shown in your reply using globals directly. I kept getting error for the statement extern char s[]; in the cfunction. Is there a reason for that ? Anyway, when i tried it with passing paramenters technique (const char *) and it worked. (See attached files). Now I need to understand what all this means and how to use it next time..
So I thank you for your help.
One final question: C seems to be too much sensitive and dependent on how you declare variables and functions. Since I like to keep functions in one place and Main () clean, is there a standard cooky cutter approach that works (most) every time ?
Thanks.
Bhal

Attachments
void cSend_Byte (unsigned char);
void cDispMsg (const char *s)
//void cDispMsg (const char *s)/* this one worked when s is sent as a parameter */
// I wanted this routine to display a message that would be passed in via s; but it does not work;
//	extern char s[];
	{
	int i;
//	void extern cSend_Byte (); not necessary as it is in the same file (?)
	for (i=0; s[i] !='\0';i++)
		cSend_Byte (s[i]);
	cSend_Byte ('\n');

	return;
	}
/***********************************************************************
Author			:	Bhal Tulpule
Date			:	26 March 2008
File			:	DEMO1.C 
Version		  	:	LVDT_V2
Hardware      	:	ADuC812 Eval Board
Modification	:	Original LVDT files are compiled.
				:	CPUT_BYTE () routine in assembly, when called worked only on first call.
				:	solution is to write C-only routines for I/O thru SBUF, AND
				:	not change the GET_BYTE, SEND_BYTE assembly routines working thru RX_BYTE etc.
				:	i.e., no sharing of routines. 
				:	UART_INTR will not clear RI, TI. It will be done by Serial I/O routines in C/ASM resp.
************************************************************************/
#pragma  DEBUG OBJECTEXTEND CODE       	/* pragma lines can contain state C51 */
#include <ADuC831.h>                    /* Include ADuC832 header file */
//#include <HT83C51.h>
#include <math.h>
#include <string.h>
//#include <stdio.h>
/*1000h,MAIN_ASSEMBLY (0100h),?C_C51STARTUP(0600h),?C?LIB_CODE(0E00h)*/

/* mux channel defines */
//T2 based on 11.0592Mhz crystal, 0xFF-0xE6 = 26*12/11.0592Mhz=28us

/* Macro definitions */

/* Externals */

extern void BOOTLOADER(void);
void cSend_Byte (unsigned char);
void cGet_Byte ();
//void cDispMsg (const char *);/* this one worked when s is sent as a parameter */
void cDispMsg (const char *);
char s[] = "It is working";
//**********************************
/* Main Loop
;/**********************************/

void main (void)
{
//	extern char s[];
//char s[] = "It is working";
	unsigned char mybyte;
//	int len;
//	int i;
	BOOTLOADER (); 
	
	do 
	{
		cGet_Byte ();
		mybyte = SBUF;
		cSend_Byte (mybyte);
		cSend_Byte (mybyte+1);
		cSend_Byte ('Y');
//		strcpy (s,"It is working");
//		cSend_Byte (strlen(s)); 
//		for (i=0; s[i] !='\0';i++)
//			cSend_Byte (s[i]);
//		cSend_Byte ('\n');
		mybyte = 0x56;	/* = ASCII for V */
		cSend_Byte (mybyte);
		cDispMsg (s);
	} while (1);

}
/*****************************************************************************/
/*
void cDispMsg (void)
//void cDispMsg (const char *s)/* this one worked when s is sent as a parameter */
// I wanted this routine to display a message that would be passed in via s; but it does not work;
//	extern char s[];
/**	{
	int i;
//	void extern cSend_Byte (); not necessary as it is in the same file (?)
	for (i=0; s[i] !='\0';i++)
		cSend_Byte (s[i]);
	cSend_Byte ('\n');

	return;
	}
*/
/*****************************************************************************/
void cSend_Byte (unsigned char x)
	{
		SBUF=x;
		while (TI==0);			/* TI is not cleared in the UART_INTR */
		TI=0;
	}
/*****************************************************************************/
void cGet_Byte ()
	{
		while (RI == 0);
		RI=0;					/* RI is not cleared in the UART_INTR */
	}

>C seems to be too much sensitive and dependent
>on how you declare variables and functions.
Yep, it's a very finicky language.

>is there a standard cooky cutter approach that works (most) every time ?
Ideally you would put your declarations in a separate header file and definitions in a separate implementation file that corresponds to the header file.

This question has already been answered. Start a new discussion instead.