Path: csiph.com!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: That depends... (Was: Regarding assignment to struct) Date: Sun, 04 May 2025 10:59:56 -0700 Organization: A noiseless patient Spider Lines: 107 Message-ID: <8634dk6yub.fsf@linuxsc.com> References: <51ba1k5h5lkj75qvfuj0ferlddpb6bi0n8@4ax.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Sun, 04 May 2025 20:00:00 +0200 (CEST) Injection-Info: dont-email.me; posting-host="f2e2a4892b4200c8deca4768c4473856"; logging-data="2660149"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/d0e7ipeH0CxndYnLLedoQybIq7XSoPNw=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:WhlZCV4GPHjg2p7roAo8vgjywLk= sha1:qVR9vBPYPRKX+8XQCbW1Zsy68CQ= Xref: csiph.com comp.lang.c:393145 Lew Pitcher writes: > On Fri, 02 May 2025 20:44:45 +0000, Kenny McCormack wrote: > >> In article <51ba1k5h5lkj75qvfuj0ferlddpb6bi0n8@4ax.com>, >> Barry Schwarz wrote: >> ... >> >>> Wouldn't it be quicker and easier to write a simple program to test >>> this rather than wait for someone to compose a response? You already >>> have 90% of the code written. >> >> That depends on what the actual personal goal is. >> >> Somehow, I don' think Lew's goal(s) (and reason for posting) are what you >> think they are. > > My goal is to add a feature to one of my older programs. The feature will > require passing a number of objects down and up the function call chain, and > I'm looking at various alternatives to accomplish this. > > ATM, it looks like I either go with "global" objects, or I change the > argument list of several functions to include about 5 more objects each. > Because these additional objects all relate to one another, I'm thinking > of grouping them in a struct, and passing a pointer to the struct back > and forth. > > But... I remembered this (apparently) seldom-used feature of being able > to pass a struct by value up and down the chain (down, as a function > argument, up as a function return value). As I've not done this before, > and I've not /seen/ it done in other peoples code, I wonder how viable > a solution it might be. It works. As far as correctness goes, there is no reason not to use it. More to say about whether and how to use it, see below. > If it is legal, then why isn't it used more often? Is it a readability/ > maintainability issue, or is it something else? I expect there are at least three reasons. One: old habits die hard. People who learned C during the K&R era (and I am one) discovered that struct types are second-class citizens: they couldn't be initialized when local to a function, or assigned to at all, to say nothing of being function arguments or return values. It became an ingrained habit: Don't Do That. Two: old habits die hard part two. The rules for struct types improved in C89/C90, but they still weren't first class, because member initializers had to be constant expressions. And if initialization didn't work, who knows what else didn't work? What became ingrained was not fact but superstition: struct types don't work except in simple ways. Three: performance concerns. Having a parameter or a return value be of struct type could be expensive in either space or time or both. In some cases the performance hit is subtle; for example, a compiler optimization that works with scalar types sometimes fails with struct types, even when the struct is no bigger than the scalar type used where the optimization succeeds. All that said, let me give some personal reactions. I don't mind using struct types for parameters or return values, when the need arises, but I find it almost never does. I admit to having a small bias against it, for no particular reason, so there is an energy barrier against using struct types in such cases, but the barrier is not insurmountable. Assuming one is using C99 or later (and these days I basically never use C90), there is a technique worth knowing that gets most of the benefit of using struct type parameters without actually giving structs as arguments. The idea is to use pointers rather than actual structs as arguments, with the struct "arguments" being locals in the calling functions. What really makes this approach work is compound literals. For example: #include typedef struct { char *p; unsigned u; } PU; void use_PU( PU * ); void call_use_PU( unsigned n ){ PU it[1] = {{ 0, 0 }}; use_PU( it ); use_PU( (PU[1]){{ malloc(n), n }} ); } In effect the function call_use_PU() is giving struct arguments, but the actual struct objects are held locally in the caller; in the first case the argument value is the address of a ordinary local object, and in the second case the argument value is the address of a compound literal object. As far as memory footprint goes this approach is the same as giving an actual struct for the argument, but without the complications of putting a struct object in the physical argument list. Having struct locals be contained in arrays of length 1 has another benefit, in that the -> operator can be used everywhere, without regard to whether the struct is a local or a pointer parameter. I find the uniformity helps streamline program development. For what it's worth, those are my thoughts on the question.