0

Say I have two arrays, dynamically allocated on the stack using C99 features. Due to the compiler's freedom of being able to reorder such arrays however it likes, and by great desire to out of bounds check, the two arrays aren't cleanly adjacent. If I just needed it to work I'd write the whole part in assembly but I'm not that serious yet.

char a[] = {'H','e','l','l','o',',',' '};
char b[] = {'W','o','r','l','d','!','\n',0};

If this were assembly, and perhaps if I knew the language better, instead of setting b, I would just grow a by perhaps just increasing the stack pointer and then copy b over.

char* b = "World!\n";
size_t b_size = 8;// or some bothered way to get the sizeof("World!\n")
char a[] = {'H','e','l','l','o',',',' '};
predict_the_future_and_run_away_if_likely_explosion(); // Maybe... just use malloc bro
if(is_magical_failure(magically_grow_array_to_size(a, sizeof(a)+b_size))
    inform_user_of_grand_tragedy_and_recover_gracefully_or_explode_in_a_fire(
        "There was not enough spacetime left available to continue.");// TODO
//... or something...
strncpy(&a[a_size], b, b_size); // This copy seems necessary

If this magically_grow_array_to_size, can exist, it would, without copy, increase the size of the stack "knowing" that a is the last thing on the stack, and complain to me that I'm stupid for trying to grow the stack for an array that is smack in the middle, and say bro, just use malloc and put it on the heap like all the other good people on stackoverflow.

If the answer is "sister, just use malloc bro", please be respectful in the comments. I know with utmost certainty that if I go into assembly and *assume the hardware architecture, and *assume there is a stack frame, and figure out how to reference the stack limit and know if It will be reached by said operation or not, everything will work.

If the answer is: c99, as elegant as it is, the feature you're looking for only got added in like version c2x or c4x or c09x... c12x, if it's within a couple years, go ahead. Beyond that, someone might appreciate it, can't promise, and hopefully I'd have accepted an answer appropriate of my time.

"don't use alloca bro" I'm having trouble parsing the answer I think; And I feel reassured as people seem to think the stack is faster than the heap~; so if alloca is slow, that's fine but why would I then go and use malloc if I don't have to? I didn't understand the it's a free lunch thing, because does that mean I can shrink my stack usage once I figure out how much I need? I feel like if I move beyond once I received a free lunch, I'll be chugging memory. Once I move beyond combining two arrays on the stack, I'd like to know I'm not using any more memory than I have to. If I could see some code on how to free lunch, considering, oh, my predicament isn't super clear.

I really don't want to have to track the length of a anywhere other than compile time, I have determined b and it's length is available and b is either in program memory or is stored on the heap. How can I free lunch using a before I've actually checked the size of a, and if I can't... well, I should be able to... and in assembly if not in C99. I still don't understand how to grow an array encouraged to be placed at the end of the stack frame... and if the endian-ness is wonky, ensure a is moved a from the middle to the beginning and add b to the end and if the endian-ness isn't wonky, just extend the size of the stack copy b in and Bob's your uncle, Alice we've done it! Should be dead simple, but apparently I'm clueless at the moment, maybe I missed the answer in plain sight, or don't know the search term but I couldn't find it.

If assembly is the best and only way to do this, if you could clear up my misconceptions about how possible or not writing cross-platform assembly is... really should be another question. I really would like a pure C99 solution if possible, if a particular flavor of assembly was perfectly defined for all C99 capable devices, or reluctantly including mostly all or vast majority of, excluding only the most obtuse of microcontrollers, and never excluding any desktop machines, I'm down for some extern asm.

Please forgive my ignorance, and the wordiness of the question, if I were smart enough for it to be shorter and concise.


With love to the comments, the following is the question: Can I merge two stack allocated arrays in place using exactly enough memory at the end but using within an order of magnitude of the memory as the below example to get there?

const char a[]={'H','e','l','l','o',',',' '};
const char b[]={'W','o','r','l','d','!','\n',0};
char c[sizeof(a)+sizeof(b)];

strncpy(c,a,sizeof(a));
strncpy(&c[sizeof(a)],b,sizeof(b));

Without assembly, I refuse to believe this is this the best I can do in terms of memory usage. I'm using twice as much stack space as strictly necessary. If this is the best that can be done, I'll accept the closed question. It's just annoying, I'd rather not go into assembly.

I can't figure out how to allocate enough space for c before defining a and b and once a and b are defined, I can't figure out how to get rid of them after defining c, other than to just do it in assembly.

It's not life threateningly critical, nobody is going to die, and I have a inefficient solution, but it is a serious question, I think. If nothing else it's just irritating that I can't get this space efficient (without assembly). Be it compiler directives or anything.

If it's closed again, I'll be asking how to do this in assembly. Because I'm lacking in comprehension.

If there is a clang solution, I'm fine with LLVM, however, cross compiler would be preferred.

If the gnu c compiler specifically, has a solution, it has good range of deployment targets as clang, if msvc only, I'd be less favorable to.

haelmic
  • 541
  • 4
  • 18
  • 3
    It is not clear what ultimate goal you are trying to accomplish here. If you need or want automatically allocated space (the C terminology for the default storage duration of objects defined inside functions is *automatic*, not *dynamic*), just define an array of the desired size. If you want to be efficient and use one large array for two strings, then define one large array to start with, and put one string at the start of the array and the other later in the array. You can also set a pointer to that one so you can refer to it easily. – Eric Postpischil Nov 26 '22 at 19:52
  • You can ask for the array to have extra room at the end when you allocate it, as in `char a[100] = "hello";` or as in `char a[5+b_size] = "hello";` – Erik Eidt Nov 26 '22 at 19:55
  • 3
    You cannot add more to the stack to extend the array because the stack grows downward (toward lower addresses) while the array goes forward (toward higher addresses), and yes, that array may be the top thing on the stack, but growing the stack will add space in front of the array (without moving anything), instead of behind the array as you're imagining. – Erik Eidt Nov 26 '22 at 19:57
  • Are you limited to plain c99? Do you accept compiler specific extensions? If so then what compiler you use? – tstanisl Nov 26 '22 at 20:07
  • 2
    What is the question? – Tom V Nov 26 '22 at 20:44
  • 1
    I'm 99.9% sure you can't do this in pure ISO C. You can do it in a pure assembly function, effectively treating the whole stack frame as one big buffer you can copy stuff around in. But you *can't* do it in *inline* `asm` statements in a C function because that would mean `c[]` would have to overlap `a[]` and `b[]`, but they all need to be in scope at the same time to use as operands to an `asm` statement. And you can't modify the address of an array after it exists. – Peter Cordes Nov 30 '22 at 13:33
  • 1
    You could make a `union { struct { char a[8], b[9]; }; char c[17]; };` if you know the sizes ahead of time. – Peter Cordes Nov 30 '22 at 13:35

0 Answers0