copying from an array of one size to an array of another - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: January 31, 2022, 09:16:40 pm
content: i need to do something like memcpy() but between a source and destination of different sizes.So I have a character display. 4 lines, 20 characters per line. I have an array that contains the data on the display, I call it the display buffer. Into that I want to copy any one of a predefined page array. It makes things simpler later to call up the page as anther dimension of an array.So I have display_buffer (rows, chars) and display_pages (pages, rows, chars). I have tried with my very basic skills of pointers and then tried memcpy(). This works only if I drop the page dimension from the source. Later I would of had languages too but clearly I may be barking up the wrong tree.I was hoping to give a function a pointer to the start of one of the pages and cycle through the 80 characters copying them into the buffer.An interrupt based display refresh routine puts the contents of the display_buffer array on the display so all I have to do is fill the buffer with what I want in the location I want it.

author: jamesglanville
author_rank: Contributor
timestamp: January 31, 2022, 09:22:00 pm
content: Quote

author: jamesglanville
author_rank: Contributor
timestamp: January 31, 2022, 09:24:40 pm
content: I can’t make the formatting work.For the source, you need & display_pages [ i ]

author: Simon
author_rank: Unknown
timestamp: January 31, 2022, 09:48:16 pm
content: Quote from: jamesglanville on January 31, 2022, 09:22:00 pmso if I use the 3 dimensional array start location in that with the & you think it will work? I'll try tomorrow, I don't look forward to 7 page sets in 7 languages as separate variables.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 31, 2022, 10:07:14 pm
content: Quote from: Simon on January 31, 2022, 09:16:40 pmCode:memcpy(display_buffer, display_pages, sizeof display_buffer);If you have languages, and sufficient memory, thenCode:#define NUM_LANGUAGES 3#define NUM_PAGES 7#define NUM_ROWS 4#define NUM_COLS 20unsigned char display_buffer;const unsigned char display_pages;void set_display(int lang, int page){if (lang >= 0 && lang < NUM_LANGUAGES && page >= 0 && page < NUM_PAGES)memcpy(display_buffer, display_pages, sizeof display_buffer);}

author: Simon
author_rank: Unknown
timestamp: January 31, 2022, 10:16:39 pm
content: I'm not sure i follow. Yes I want to do the first bit. create an array as a constant that contains the lot, that way I don't put it all into RAM, I could but I don't want to splurge resources as I am at the start of working for this company starting coding my own stuff from scratch and I don't want a find myself limited on a project in the future because I am reusing crappy wasteful code I wrote.Most of the text is fixed so if I want to change page I load the entire static base page then update the specific character locations that show runtime variables as they change.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 31, 2022, 11:22:48 pm
content: Right. So, in addition to each page, you'll have some kind of list of variables displayed and how the values are formatted.In any case, the core point is that if you have an arrayTYPEname;thennamerefers to thei3'th sub-array,TYPE. Also,(void *)(name) == (void *)&(name)Similarly,namerefers to the'th sub-array,TYPE, and(void *)(name) == (void *)&(name)So, if you have sayconst unsigned char display_page;thendisplay_pagerefers to a two-dimensional array ofconst unsigned charwith dimensions. Becausememcpy()takesvoid *, referring to the sub-array is converted to a void pointer to its first element. Thus,memcpy(destination, display_page, sizeof display_page);copies the 80 bytes of pagepagenumto destination.Thesizeof display_pageworks, becausedisplay_pagerefers to aarray ofconst unsigned char, and thesizeofoperator only examines its type; no memory is ever accessed.Indeed, if you have saystruct somestruct *pointer;then(sizeof *pointer == sizeof (struct somestruct)), because thesizeofoperator does notevaluateits argument, it only examines it for thetypeof the argument. There is no problem even ifpointer == NULL, because the operator does not causepointerto be dereferenced. More importantly,Code:int x = 4;printf("sizeof ++x = %zu\n", sizeof ++x);printf("x = %d\n", x);will printx = 4(and NOTx = 5), simply becausesizeofis the special size-examining operator, and not a function-like thing.

author: Simon
author_rank: Unknown
timestamp: February 01, 2022, 08:08:42 am
content: I'm sort of aware that using the name of an array with no index is a pointer to the first element so it sounds like you are talking about this same principle where leaving out sub array indexes means I am pointing to the start of the sub array that is listed like pages is a pointer to the start of pages.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 01, 2022, 08:29:58 am
content: Quote from: Simon on February 01, 2022, 08:08:42 amYes, I think you got it.Consider the following example C program:Code:#include <stdio.h>#define XSIZE 4#define YSIZE 4#define ZSIZE 4void show_3d(const char *title, int map){printf("%s:\n", title);for (int z = 0; z < ZSIZE; z++) {printf(" z = %d:\n", z);for (int y = 0; y < YSIZE; y++) {printf(" ");for (int x = 0; x < XSIZE; x++) {printf(" %3d", map);}printf("\n");}}printf("\n");}void show_2d(const char *title, int map){printf("%s:\n", title);for (int y = 0; y < YSIZE; y++) {printf(" ");for (int x = 0; x < XSIZE; x++) {printf(" %3d", map);}printf("\n");}printf("\n");}void show_1d(const char *title, int map){printf("%s:\n ", title);for (int x = 0; x < XSIZE; x++) {printf(" %3d", map);}printf("\n\n");}int main(void){int map;for (int z = 0; z < ZSIZE; z++) {for (int y = 0; y < YSIZE; y++) {for (int x = 0; x < XSIZE; x++) {map = z*100 + y*10 + x;}}}show_3d("3D", map);show_2d("2D with z=0", map);show_2d("2D with z=1", map);show_1d("1D with z=2 and y=3", map);show_1d("1D with z=3 and y=0", map);return 0;}Writing and running tests like this with all error checking enabled (-Wall -Wextra -pedantic -std=c99) is an useful way to explore these things.The output isCode:3D:z = 0:0 1 2 310 11 12 1320 21 22 2330 31 32 33z = 1:100 101 102 103110 111 112 113120 121 122 123130 131 132 133z = 2:200 201 202 203210 211 212 213220 221 222 223230 231 232 233z = 3:300 301 302 303310 311 312 313320 321 322 323330 331 332 3332D with z=0:0 1 2 310 11 12 1320 21 22 2330 31 32 332D with z=1:100 101 102 103110 111 112 113120 121 122 123130 131 132 1331D with z=2 and y=3:230 231 232 2331D with z=3 and y=0:300 301 302 303

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 02, 2022, 03:10:33 am
content: Sorry for the refloat, but wouldn't this do the job straight away?I don't think it's UB, the compiler knows both src and dst are the same type, I use this approach often, never had any problem.Code:typedef struct{char d;}dispbf_t;dispbf_t display_buffer;dispbf_t display_pages;void store_page (){display_pages = display_buffer;display_pages = display_buffer;}void access_array(){display_buffer.d = 0;display_pages.d = 0;}

author: Siwastaja
author_rank: Super Contributor
timestamp: June 02, 2022, 06:43:05 am
content: Yes! When you realize arrays can be inside structs, and struct objects are like any variables (copied by assignment, passed by value, returned from a function...) C suddenly seems to become a higher level language!Just be aware of such high-level language traps: from simple assignment operation, it's hard to intuitively see it's a large copy operation. Some leave thetypedefaway so that they need to explicitly write the struct keyword, working as a reminder it's likely going to be more than just a few bytes.Whenever you can force the compiler to inline a function call, you can pretty safely pass large structs by value, and return them, and compiler will optimize all the excess copying crap out. This makes C look pretty high-level, and code is readable.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 02, 2022, 08:27:42 am
content: (My point above was that one can avoid the copy operation completely.)

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 02, 2022, 09:30:22 am
content: AFAIK, the compiler runs a memcpy under the hood when copying structs.I guess it'll made inline optimizations for small data.Of course, that's not a simple int copy, but you must know what you're doing.I like it over memcpy or other methods, gives very compact and neat code, also you don't have to think about addressing, size, etc...

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 03, 2022, 06:30:56 pm
content: Quote from: DavidAlfa on June 02, 2022, 09:30:22 amYes, just like memcpy itself.Quote from: DavidAlfa on June 02, 2022, 09:30:22 amYes. It makes manipulating your data higher-level instead of a mix of high- and low-level that is pretty common in C.Likewise, for zero'ing out a whole struct (which can contain anything you want including arrays) outside of initialization, you can use C99+ compound literals.Like in your example:Code:display_buffer = (dispbf_t){ 0 };It's higher-level than using memset().