What is going on here?
When I run this test, the first 3 are bytes of ACSII, read as ints, as expected. But admin_pass and user_pass etc are supposed to be char[8] or [32]. Why the trash printed after the specified lengths? Specifically, why do the *_pass: printfs not print 8 chars? And where is it grabbing the extra chars from?
Using Dynamic C 10.64
Output:
ip_addr: 12849
pwm_freq: 13877
duty_cycle: 14391
admin_pass: 90abcdefghijklmn78561234
user_pass: ghijklmn78561234
device_name: opqrstuvwxyz~!@#$%^&*()_+,./<>?{90abcdefghijklmn78561234
Bringing up Main
Source:
unsigned long ip_addr;
int pwm_freq;
int duty_cycle;
char user_pass[8];
char admin_pass[8];
char device_name[32];
void main(void)
{
char fill[56];
strcpy(fill, "1234567890abcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+,./<>?{}{}{}{}{}");
writeUserBlock(0, &fill, sizeof(fill));
//test
readUserBlock(&ip_addr, 0, sizeof(ip_addr));
printf("ip_addr: %d
", ip_addr);
readUserBlock(&pwm_freq, 4, sizeof(pwm_freq));
printf("pwm_freq: %d
", pwm_freq);
readUserBlock(&duty_cycle, 6, sizeof(duty_cycle));
printf("duty_cycle: %d
", duty_cycle);
readUserBlock(&admin_pass, 8, sizeof(admin_pass));
printf("admin_pass: %s
", admin_pass);
readUserBlock(&user_pass, 16, sizeof(user_pass));
printf("user_pass: %s
", user_pass);
readUserBlock(&device_name, 24, sizeof(device_name));
printf("device_name: %s
", device_name);
printf("
Bringing up Main
");
}
BTW, I cannot get any of the userBlockArray samples to compile.
userblock_sample.c fails with a type error in a LIB:
line 1284 : WARNING IDBLOCK.LIB : Wrong type for parameter 1.
line 1284 : WARNING IDBLOCK.LIB : Converting const far void * to incompatible pointer type void * const *
/********************************************************************
userblock_sample.c
Z-World, 2002
This program demonstrates the use of the writeUserBlockArray()
and readUserBlockArray() functions. writeUserBlockArray() allows
the writing of sets of data to the user block at once. This is
particularly useful for mirrored user blocks when you need a
coherent snapshot of data that is scattered across memory. If
you used writeUserBlock() in a loop over the data, you would not
have a coherent snapshot if a power cycle happened in the middle
of writing. writeUserBlockArray(), however, does not validate
the new data until it has all been completely written, hence
guaranteeing a coherent snapshot even if a power cycle happens
in the middle of the write.
********************************************************************/
#class auto
/* Set the size of the test string */
#define TEST_STRING_LEN 20
void main(void)
{
/* Create variables for our test data */
struct test_struct {
int foo;
long bar;
} test_data;
long test_long;
char test_string[TEST_STRING_LEN];
/*
* Create arrays to hold pointers to the data we want to save, as well
* as the lengths
*/
void* save_data[3];
unsigned int save_lens[3];
/* Initialize the test data */
test_data.foo = 12;
test_data.bar = 34;
test_long = 5678;
strcpy(test_string, "Hello!");
/* Print out what we are saving */
printf("Saving...
");
printf("test_data.foo = %d
", test_data.foo);
printf("test_data.bar = %ld
", test_data.bar);
printf("test_long = %ld
", test_long);
printf("test_string = %s
", test_string);
/* Save the data to the user block */
save_data[0] = &test_data;
save_lens[0] = sizeof(test_data);
save_data[1] = &test_long;
save_lens[1] = sizeof(test_long);
save_data[2] = test_string;
save_lens[2] = TEST_STRING_LEN;
writeUserBlockArray(0, (const void * const *) save_data, save_lens, 3);
/*
* Clear our variables (to ensure that when we read the data back, it
* is not correct simply because nothing was read).
*/
test_data.foo = 0;
test_data.bar = 0;
test_long = 0;
strcpy(test_string, "Not correct!");
/*
* Read back our saved values (note that you could also just use
* readUserBlock() in a loop)
*/
readUserBlockArray(save_data, save_lens, 3, 0);
/* Print out what we are loading */
printf("
Loading...
");
printf("test_data.foo = %d
", test_data.foo);
printf("test_data.bar = %ld
", test_data.bar);
printf("test_long = %ld
", test_long);
printf("test_string = %s
", test_string);
}
OK
I updated Dynamic C to 10.72. The samples now run, but my code still outputs the same thing.
Reading the Function guide, printf conversion reads:
The argument is a pointer to a character array. Characters from the
string are written up to (but not including) a null terminator. If the precision is specified, no more than that many characters are
written. The array must contain a null terminator if the precision
is not specified or is greater than the size of the array.
I’m guessing that readUserBlock() does not put a null at the end of the read data. I’m specifying sizeof(admin_pass) in the read and so my char array is not now null-terminated. But, then the output suggests there is a null between 4 and 5 in the fill string…
Hello
char fill[56];
strcpy(fill, “1234567890abcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+,./<>?{}{}{}{}{}”);
I have countged this a couple of times. The strcpy is attempting to copy 66 characters into a buffer who length is 56. Nothing good can come of this.
My standard operating procedure is to memset all character buffers to all nuls at the beginning and before reuse. This can solve all manner of sin.
The answer to your first question is that the strings have no nul terminator as stored in your example and so printf will not stop at what you think is the end of the string.
try:
char admin_pass[9];
readUserBlock(&admin_pass, 8, sizeof(admin_pass));
admin_pass[8] = 0;
printf("admin_pass: %s
", admin_pass);
for example.
BTW what version of DC and what board?
Regards,
Peter
Thanks all for info and tips -I think it is straightened out in the head. What mystified me was that if printf() didn’t stop until it saw a null char, then why did it stop at all before the end of the 56/66 char string written to the memory location just before; it seems the &admin_pass ptr in RAM was in a memory location near &fill in RAM, but not contiguous, and I was thinking NVRAM that I’d written which was contiguous. I’ll bet if I’d printed out the main memory around the pointers it would have been clear.
The defective example in 10.64 didn’t help. 10.72 examples work fine, and I found another good ex code: http://www.shdesigns.org/rabbit/locateip.shtml
I need to change and store the IP config etc of a PWM device from a web interface, so it will suit well.