Actionary

A man is valued by his works, not his words!

Structure Assignment and Its Pitfall in C Language

Problem

There is a structure type defined as below:

1
2
3
4
5
typedef struct __map_t {
    int code;
    char name[NAME_SIZE];
    char *alias;
}map_t;

If we want to assign map_t type variable struct2 to sturct1, we usually have below 3 ways:

1
2
3
4
5
6
7
8
9
10
/* Way #1: assign the members one by one */
struct1.code = struct2.code;
strncpy(struct1.name, struct2.name, NAME_SIZE);
struct1.alias = struct2.alias;

/* Way #2: memcpy the whole memory content of struct2 to struct1 */
memcpy(&struct1, &struct2, sizeof(struct1));

/* Way #3: straight assignment with '=' */
struct1 = struct2;

Consider above ways, most of programmer won’t use way #1, since it’s so stupid ways compare to other twos, only if we are defining an structure assignment function. So, what’s the difference between way #2 and way #3? And what’s the pitfall of the structure assignment once there is array or pointer member existed? Coming sections maybe helpful for your understanding.

The difference between ‘=’ straight assignment and memcpy

The struct1=struct2; notation is not only more concise, but also shorter and leaves more optimization opportunities to the compiler. The semantic meaning of = is an assignment, while memcpy just copies memory. That’s a huge difference in readability as well, although memcpy does the same in this case.

Copying by straight assignment is probably best, since it’s shorter, easier to read, and has a higher level of abstraction. Instead of saying (to the human reader of the code) “copy these bits from here to there”, and requiring the reader to think about the size argument to the copy, you’re just doing a straight assignment (“copy this value from here to here”). There can be no hesitation about whether or not the size is correct.

Consider that, above source code also has pitfall about the pointer alias, it will lead dangling pointer problem (It will be introduced below section). If we use straight structure assignment ‘=’ in C++, we can consider to overload the operator= function, that can dissolve the problem, and the structure assignment usage does not need to do any changes, but structure memcpy does not have such opportunity.

The pitfall of structure assignment:

Beware though, that copying structs that contain pointers to heap-allocated memory can be a bit dangerous, since by doing so you’re aliasing the pointer, and typically making it ambiguous who owns the pointer after the copying operation.

If the structures are of compatible types, yes, you can, with something like:

1
memcpy (dest_struct, source_struct, sizeof(dest_struct));

} The only thing you need to be aware of is that this is a shallow copy. In other words, if you have a char * pointing to a specific string, both structures will point to the same string.

And changing the contents of one of those string fields (the data that the char points to, not the char itself) will change the other as well. For these situations a “deep copy” is really the only choice, and that needs to go in a function. If you want a easy copy without having to manually do each field but with the added bonus of non-shallow string copies, use strdup:

1
2
memcpy (dest_struct, source_struct, sizeof (dest_struct));
dest_struct->strptr = strdup(source_struct->strptr);

This will copy the entire contents of the structure, then deep-copy the string, effectively giving a separate string to each structure. And, if your C implementation doesn’t have a strdup (it’s not part of the ISO standard), you have to allocate new memory for dest_struct pointer member, and copy the data to memory address.

Example of trap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NAME_SIZE   16
typedef struct _map_t {
    int code;
    char name[NAME_SIZE];
    char *alias;
} map_t;

int main()
{
    map_t a, b, c;

    /* initialize the a's members value */
    a.code = 1024;
    snprintf(a.name, NAME_SIZE, "Controller SW3");
    char *alias = "RNC&IPA";
    a.alias = alias;

    /* assign the value via memcpy */
    memcpy(&b, &a, sizeof(b));

    /* assign the value via '=' */
    c = a;
    return 0;
}

Below diagram illustrates above source memory layout, if there is a pointer field member, either the straight assignment or memcpy, that will be alias of pointer to point same address. For example, b.alias and c.alias both points to address of a.alias. Once one of them free the pointed address, it will cause another pointer as dangling pointer. It’s dangerous!!

Alt text

Conclusion

  • Recommend use straight assignment ‘=’ instead of memcpy.
  • If structure has pointer or array member, please consider the pointer alias problem, it will lead dangling pointer once incorrect use. Better way is implement structure assignment function in C, and overload the operator= function in C++.

Reference:

Retrospective of My 2012

In our organization, we have a basic rule is: If you make retrospective for one specific sprint, you shall finish it in the sprint time slot. So it against our rule since I make 2012 retrospective in 2013, but later than never. I believe retrospective since I have ran agile for several years, I know it can benefit me.

My grandpa told my mother, and my mother told me that you have to look back and reflect on your life every night before you go to bed. It’s difficult for me, because I always tell story to my kid during that time, or do others, you know that… So I demand me shall make retrospective at least once annually.

How have things gone?

2012, some small changes in my job. I resigned my R&D manager job, and selected R&D coach job. Make this decision, it was based on my interesting, and strength(I think so). Some other reason is that I like to try some new rather than maintain old, I’d like do some challenge works. I selected be a technical person rather than politician in such R&D company. From this point, I think I kept a clear mind, but somethings I have to recognize is that I learn a lot from this management position. Understand what you want is more important than what you have been.

Later, in May, June, Our team and I held a clean code contest successfully, it got the supports from the heads, so it taught me that you have to align your idea with your boss, that you will make thing simple. And comming month, I sold my codemetrics idea, delivered some training and in the end of 2012, held the coderetreat global day of 2012 in Hangzhou City. Made such lots of activities in company internally, so the influence just only limited in our company, that’s a problem, personally think this shall be improved in 2013.

Another interesting works is have a taste on the translation works, in 2012, finish the Codermetrics: Analytics for Improving Software Teams to Chinese version translation. And finish personal owned embedded device development

Books I have read:

Books I’m reading:

What improvements are needed

A little fat, shall make a plan to resolve this problem. I shall learn some web technical in this web era, and be more active in open communities, learn more, and also shall seriously consider where I go. Maybe leave this country is a choice, even it’s not easy for a married man, but some friends made good example for this, so practice English communication skill is more important than before. I’ll continually post English blog here, translate English post to Chinese, and practice more. New year, hope can breathe fresh air, drink clear warter, and eat nontoxic food.

Build Up Octopress Style Blog Site

Why I choose octopress?

I’m a programmer, and I’m also a lazy guy. One hand, a programmer will encounter quite a lots of questions and problems, such as algorithom making, post reading, open source community contribution, and bug fixing. On the other hand, I’m lazy, a lazy programmer will forget a lots of things, because he is lazy, and too things to memorize, so write them done on the source code will be a good way.

Sometimes I like blogging, just sometimes. In the eariler time, I blog on myspace in Microsoft host website, and later, they decide to shut down the host, and push me transferring my owned stuff to wordpress.com, that is a huge platform, million people blog on that, varios of functionalities even I just use little of them. I’m not a proffsional editor, and I’m living in China, the country where cannot visit facebook, twitter, youtube, and wordpress. But thank godness, we can visit github.com in China.

Always expect there will be a tiny framework, programmer can post blog likes programming. Thanks godness again, octopress can do it…., thank god, thank author, thank all the people who guide me know this.

My octopress git repository

I follow the official guide to setup octopress, that I can easily install the octopress on my Linux OS. After finish this, I was recommended to build up my blogs on github, since there is programmer’s private plots, we can plant anything what we want. And I managment my octopress and draft like below illustrates:

Alt text

Then I follow up the second guideline to deploy octopress blogs in github. But another problem is comming, during you execute rake setup_github_pages, rake will ask you input your blog repository in git protocal (actually in SSH protocal), that’s my office network cannot support, in our office, we can support https. How I can resolve this issue?

Tips

Open the Rakefile which is under octopress folder, and jump to this code snippet:

1
2
3
4
5
6
7
8
9
10
11
task :setup_github_pages, :repo do |t, args|
  if args.repo
    repo_url = args.repo
  else
    puts "Enter the read/write url for your repository"
    puts "(For example, 'git@github.com:your_username/your_username.github.com)"
    repo_url = get_stdin("Repository url: ")
  end
  user = repo_url.match(/:([^\/]+)/)[1]
  branch = (repo_url.match(/\/[\w-]+\.github\.com/).nil?) ? 'gh-pages' : 'master'
  project = (branch == 'gh-pages') ? repo_url.match(/\/([^\.]+)/)[1] : ''

You can change the code to support httpsurl, the code like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
task :setup_github_pages, :repo do |t, args|
  if args.repo
    repo_url = args.repo
  else
    puts "Enter the read/write url for your repository"
    puts "(For example, 'git@github.com:your_username/your_username.github.com'"
    puts "           or 'https://github.com/your_username/your_username.github.com')"
    repo_url = get_stdin("Repository url: ")
  end

  protocol = (repo_url.match(/(^git)@/).nil?) ? 'https' : 'git'
  if protocol == 'git'
    user = repo_url.match(/:([^\/]+)/)[1]
  else
    user = repo_url.match(/github\.com\/([^\/]+)/)[1]
  end

  branch = (repo_url.match(/\/[\w-]+\.github\.com/).nil?) ? 'gh-pages' : 'master'
  project = (branch == 'gh-pages') ? repo_url.match(/\/([^\.]+)/)[1] : ''

After that, rake can support https. Others, I only follow the official guideline, now you can see this post means I have successfully built up my blogs, and post blogs in office.

Post blogs like programming, if you are programmer, just do it. Cheers!