LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-15-2011, 12:01 AM   #1
stf92
Senior Member
 
Registered: Apr 2007
Location: Buenos Aires.
Distribution: Slackware
Posts: 4,442

Rep: Reputation: 76
Assigning variables to multiple fields in a structure is tiresome.


Hi:

I have

struct foo {
int foo1;
int foo2;
........
int foo9;
}

and I must initialize its fields with there respective values. So I must do

foo.foo1= val1;
foo.foo2= val2;
................
foo.foo9= val9;

Is not this too much work? In Pascal, you can do this with:

with foo begin
foo1= val1;
foo2= val2;
.........
foo9= val9;
end;

Is there not a similar way in C (not C++)?
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 08-15-2011, 04:06 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
There are other ways in C; for example:

Code:
struct Foo
{
   int   x;
   int   y;
   char* str;
};

struct Foo f1 = { 1, 2, "hello" };      // using this format, all values must be specified

/* or */

struct Foo f2 = { .y = 2, .str = "hello", .x = 1 };  // using this format, some fields may be omitted.
 
2 members found this post helpful.
Old 08-15-2011, 09:00 AM   #3
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by dwhitney67 View Post
Code:
struct Foo f1 = { 1, 2, "hello" };      // using this format, all values must be specified
You can actually leave off initializers at the end with this, e.g. struct Foo f1 = { 1, 2 };, but not in the middle.
Quote:
Originally Posted by dwhitney67 View Post
Code:
struct Foo f2 = { .y = 2, .str = "hello", .x = 1 };  // using this format, some fields may be omitted.
I'd prefer using this method all the time, except it isn't allowed for C-struct initialization in C++. I generally use the y: 2 gcc extension; however, that doesn't respond well if the members are used out of order (it's really only good for clarity or skipping members in the middle somewhere.)

This is kind of a joke, but it certainly works using gcc statement expressions. Since you can only use {} to initialize (and not to assign) this is the lazy-man's way of copying members from multiple locations.
Code:
struct Foo f1 = { 0, 0, 0 };
//f1 = { 1, 2, "hello" }; //fail!
memcpy(&f1, ({struct Foo v = { 1, 2, "hello" }; &v;}), sizeof f1);
Kevin Barry

edit: To continue entertaining myself...
Code:
#define GCC_COPY_START(first) \
  memcpy(&first, ({typeof(first) v =

#define GCC_COPY_END(first) \
  ; &v;}), sizeof(typeof(first)));

//...

struct Foo f1 = { 0, 0, 0 };

GCC_COPY_START(f1)
  { 1, 2, "hello" } //(can't use this as a macro argument)
GCC_COPY_END(f1)

Last edited by ta0kira; 08-15-2011 at 09:12 AM.
 
Old 08-15-2011, 09:23 AM   #4
stf92
Senior Member
 
Registered: Apr 2007
Location: Buenos Aires.
Distribution: Slackware
Posts: 4,442

Original Poster
Rep: Reputation: 76
Thank you dwhitney67.

@ta0kira:
memcpy(&f1, ({struct Foo v = { 1, 2, "hello" }; &v;}), sizeof f1);

Humn... If these are the ways to assign a struct in C, then I think Pascal wins, with its 'with <struc_name> begin end' construct.
 
Old 08-15-2011, 09:40 AM   #5
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by stf92 View Post
@ta0kira:
memcpy(&f1, ({struct Foo v = { 1, 2, "hello" }; &v;}), sizeof f1);

Humn... If these are the ways to assign a struct in C, then I think Pascal wins, with its 'with <struc_name> begin end' construct.
This isn't actually C; it's just something gcc allows. With the macros I think it's close to Pascal's. I've actually never used that in real code, though, nor do I plan to.

Not that I'm proposing this as a solution, but adding { and } to the macros makes it a competitor:
Code:
#define WITH(first) \
  memcpy(&first, ({typeof(first) v = {

#define END(first) \
  }; &v;}), sizeof(typeof(first)));

//...

struct Foo f1 = { 0, 0, "old string" };

//sometime later I want to change f1...

WITH(f1)
  .y = 1,
  .x = 2,
  .str = "hello"
END(f1)
I'm proud of myself. This almost certainly won't compile on anything besides gcc.
Kevin Barry
 
Old 08-15-2011, 11:19 AM   #6
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by ta0kira View Post
This isn't actually C; it's just something gcc allows. ...
It is C99, which allows anonymous data structures like this one. See http://www.open-std.org/JTC1/SC22/wg...docs/n1124.pdf for reference.
 
2 members found this post helpful.
Old 08-15-2011, 12:03 PM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Sergei Steshenko View Post
It is C99, which allows anonymous data structures like this one. See http://www.open-std.org/JTC1/SC22/wg...docs/n1124.pdf for reference.
Not the way I had it written. I wrote it as a compound statement, but changing it to this makes it C99-compliant (after reviewing your reference):
Code:
memcpy(&f1, &(struct Foo) { 1, 2, "hello" }, sizeof f1);
Kevin Barry
 
Old 08-15-2011, 01:21 PM   #8
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
C99 supports compound literals. For example, given
Code:
struct foo {
	float a;
	long  b;
	int   c;
	char  d;
};

struct foo f1, f2, f3;
these statements
Code:
f1 = (struct foo){ 1.0f, 2L, 3, 4 };

f2 = (struct foo){ .c = 3,
                   .a = 1.0f,
                   .d = 4,
                   .b = 2 };

f3 = f1;
are perfectly valid C99, and all three structures will contain the same values. The first two are compound literals, and the third one is a structure assignment. The structure will be assigned as an opaque block, not field-by-field; most compilers will use either memcpy() or open-coded equivalent.

For compiling C99 code (with all warnings, including pedantic ones) with GCC, I recommend using
Code:
gcc -std=c99 -Wall -pedantic ...
Outside interface declarations (header files) I could not care less about compatibility with C++, since C++ is a completely different language. They are related, yes, and you can compile most ANSI C and C89 code with a C++ compiler, but that's it.
 
Old 08-15-2011, 01:35 PM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
C99 supports compound literals.
That's what I used in my previous post; however, the post in question used a compound statement. This is not valid C99:
Code:
struct foo {
        float a;
        long  b;
        int   c;
        char  d;
};

int main()
{
  struct foo f1, f2, f3;
  f1 = ({
    struct foo f4 = f2;
    f4.a += f3.a;
    f4.b -= f3.b;
    f4;
  });
}
Compile it with gcc -std=c99 -pedantic.
Kevin Barry
 
Old 08-16-2011, 09:53 PM   #10
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by ta0kira View Post
That's what I used in my previous post
I was replying to the OP directly.

I thought the thread had become a bit confusing, so I wrote my reply as a standalone post, not referring to any of the previous posts, for clarity.

For example, in your post you refer to, the use of memcpy() is utterly unnecessary.
Code:
(struct Foo)f1 = (struct Foo){ 1, 2, "Hello" };
behaves exactly the same way, including type-punning f1 if it happens to be some other (compatible) type, and is arguably much more readable C99. (If f1 is of struct Foo type, the first cast should of course be dropped. I only included it so that the statement is equivalent to the one you used.)

The latter form is also much easier for compilers to optimize. Taking the address of a variable usually means the compiler will not optimize it away, e.g. in registers. Although x86 is register-poor, in other architectures f1 might be entirely stored in registers; explicitly using memcpy() to assign it will force it to be stored in memory.

Quote:
Originally Posted by ta0kira View Post
This is not valid C99:
Code:
struct foo {
        float a;
        long  b;
        int   c;
        char  d;
};

int main()
{
  struct foo f1, f2, f3;
  f1 = ({
    struct foo f4 = f2;
    f4.a += f3.a;
    f4.b -= f3.b;
    f4;
  });
}
Well, no, but why would you use something like that anyway? Assignment
Code:
  f1 = (struct foo){ f2.a + f3.a, f2.b - f3.b, f2.c, f2.d };
is functionally equivalent, and valid C99, although you do need to name all fields (from f2). Assignments
Code:
  f1 = f2;
  f1.a += f3.a;
  f1.b -= f3.b;
are also equivalent (and valid C99), but is the more typical pattern.

To the OP: readability is much more important than brevity. I personally use C99, especially compound literals in structure assignments. For partial assignments, I always use the last code sample above; that is, assign each field separately.

If you have a more complex structure in C99, with certain partial assignments done often, then it is a good idea to group those into substructures. You'll write less code that way, too. Here is an example:
Code:
struct point {
	double	x;
	double	y;
};

struct line {
	struct point	p1;
	struct point	p2;
};

/* Define a line with p1.x <= p2.x */
struct line define_line(struct point const p1, struct point const p2)
{
	if (p1.x <= p2.x)
		return (struct line){ .p1 = p1, .p2 = p2 };
	else
		return (struct line){ .p1 = p2, .p2 = p1 };
}
If you have even more complex assignments you do often, put them into separate functions, and mark the functions static inline . In C99, that means the function is local (not seen at all by other object files) and should be inlined. It is just as fast as writing a complex preprocessor macro to do it. (If not, blame the compiler; it really should be.)

I really hope I'm not just confusing the OP further,
 
Old 08-17-2011, 08:02 AM   #11
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
I was replying to the OP directly.

I thought the thread had become a bit confusing, so I wrote my reply as a standalone post, not referring to any of the previous posts, for clarity.

For example, in your post you refer to, the use of memcpy() is utterly unnecessary.
Like I said in that other post, I wasn't proposing it as a solution and it's not something I've ever used in real code. Everything subsequent was just an effort to clear up confusion stemming from a satirical, yet technically valid, solution.
Kevin Barry
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Assigning Structure object's variable outside main() gives parse error thelink123 Programming 7 09-03-2010 06:41 AM
Assigning variables in a bash for loop JDska55 Linux - Newbie 6 06-18-2009 03:37 PM
Assigning variables by awk(?) bioinformatics_guy Linux - Newbie 2 02-19-2009 12:01 PM
help with a little perl script and assigning variables sal_paradise42 Programming 8 10-15-2008 12:44 PM
C++ Assigning attributes to variables ? xconspirisist Programming 16 11-05-2003 06:08 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:59 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration