Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > [TinyCC] sizeof of element of struct returned by function

Reply
Thread Tools

[TinyCC] sizeof of element of struct returned by function

 
 
James Kuyper
Guest
Posts: n/a
 
      02-21-2013
On 02/21/2013 06:41 AM, Maciej Labanowicz wrote:
> On 20 Feb, 20:10, Shao Miller <(E-Mail Removed)> wrote:
>> Redundant parentheses for the 'sizeof' operator.

>
> This is a style that I prefer.
> My experience shows that sometimes using of parentheses is a good
> idea.
> It makes that the code review is simpler, example:
> - if (a + b * c)
> + if (a + (b * c))
> BTW: I remember that my university teacher has always complaining
> about the redundant parentheses, he has mentioned that I should
> know perfectly priority of operators.
> After that I have started to work in private company,
> where such practice is forbidden.
> Parentheses are your friend.


Putting in so many unnecessary parentheses made your expressions very
confusing - it took me a lot longer to figure them out than it should have.

> Another example of the redundant code is the
> initialization of 'result' in function 'fun'.
> But this is also a style that I prefer.
> Any variable should be initialized at begining.


In this case, you can trivially give the variable it's final value at
the point of definition, so why not do so?

bar_t * fun(foo_t * foo_ptr) {
bar_t * result = &(foo_ptr->bar);
printf("++ fun(foo_ptr = %p)\n", (void *)foo_ptr);
printf("-- fun(...) = %p\n", (void *)result);
return result;
}

I'm opposed to the idea of initializing a variable with anything other
than a value that is intended to be used. I will delay definition of the
variable as long as possible in order to make this happen. In C99, which
allows inter-mixed declarations and statements, it's possible to delay
definition a great deal. However, if I reach the point where it's no
longer possible to delay definition of the variable, and I still can't
give it a value that's actually intended to be used, I leave it
uninitialized.

My reason for this policy is that most modern compilers do a very good
job of checking whether or not a variable has been given a value before
it's first use. By initializing it with a value never intended to be
used, you are disabling that check. You might end up unintentionally
using the value that was never intended to be used.

> For example, a someone has fixed this code with:
> if (foo_ptr) {
> result = &(foo_ptr->bar);
> }
> then function is still correctly working.
> In case the initialization is redundant then
> an optimizer will remove the code during compilation process.


Not always - but redundancy isn't the primary reason I'm opposed to this
practice.

> It is very hard to diagnose bugs that depends on the uninitialized
> variable, especially
> if it occures only ones per a week and only on client side (taken from
> real life).


In my experience, modern compilers are very good at diagnosing possible
use of uninitialized variables. Achieving certainty about whether an
uninitialized variable will be used is exactly equivalent to solving the
halting problem, but if you allow for a small number of false positives,
such problems can be identified quite easily - in case of doubt, flag it
as dangerous. If the code's so confusing that the compiler can't be
certain whether the variable will be used while uninitialized, it's too
complicated for me to be justifiably certain about it, either. In that
case, I will relent and give it an initial value that's not intended to
be used - usually one deliberately chosen to produce a spectacular
failure if it ever does get used. I would never choose a value that's
intended to allow the routine to keep working normally - if something
has happened that wasn't supposed to happen, I want to know about it as
soon as possible.
--
James Kuyper
 
Reply With Quote
 
 
 
 
Shao Miller
Guest
Posts: n/a
 
      02-21-2013
On 2/21/2013 06:41, Maciej Labanowicz wrote:
> On 20 Feb, 20:10, Shao Miller <(E-Mail Removed)> wrote:
>> Redundant parentheses for the 'sizeof' operator.

>
> This is a style that I prefer.


Ok, I respect that, then. If I could make a tiny suggestion: Since you
use 'if (', perhaps you could use 'sizeof (' instead of 'sizeof('? This
tiny change would have some infinitesimally smaller chance of
perpetuating 'sizeof' confusion for people who try to learn C from
source code... Assuming that you use 'func(' and 'macro(' rather than
'func (' and 'macro ('.

> My experience shows that sometimes using of parentheses is a good
> idea.
> It makes that the code review is simpler, example:
> - if (a + b * c)
> + if (a + (b * c))


Yes, sometimes I introduce redundant parentheses with infix operators,
too, if it seems to make code more readable, as you say. Your example
is nice.

> BTW: I remember that my university teacher has always complaining
> about the redundant parentheses, he has mentioned that I should
> know perfectly priority of operators.
> After that I have started to work in private company,
> where such practice is forbidden.


Which practice? This doesn't make sense, to me... Adding redundant
parentheses is a practice, because you have to choose where to put them.
Choosing not to add them is not a practice, because you simply don't
make any choices about where to add them. Can you explain this policy a
bit more? Does the policy explain exactly when and where to add them?

> Parentheses are your friend.
>


Agreed that they can be, but only if they contribute to clarity. In the
case of the 'sizeof' operator, they've confused people into thinking
it's a function or a macro. If 'sizeof' had been '_Sizeof' all along,
then at least it would have a funny look that learners might think twice
about. As it is, code like:

x = printf("Hello, world!\n");
x = sizeof("Hello, world!\n");

has two lines which look so similar that a lot of novices get 'sizeof'
and 'strlen' confused. If you can teach something with your code, then
your code can go beyond functional and readable, towards instructional.
That's not important to everyone.

> Another example of the redundant code is the
> initialization of 'result' in function 'fun'.
> But this is also a style that I prefer.


Ok. Do you use special values as a sort of "trap", so that clients can
report observations and it helps you to debug the problem?

> Any variable should be initialized at begining.
> For example, a someone has fixed this code with:
> if (foo_ptr) {
> result = &(foo_ptr->bar);
> }
> then function is still correctly working.
> In case the initialization is redundant then
> an optimizer will remove the code during compilation process.
> It is very hard to diagnose bugs that depends on the uninitialized
> variable, especially
> if it occures only ones per a week and only on client side (taken from
> real life).


Maybe that's why you are typing posts involving some of the subtleties
of C? So that you can fix a compiler that isn't good at warning about
use of uninitialized objects? I can think of a couple that do a pretty
good job of it, but obviously that's not universal.

--
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily," -- Richard Harter
 
Reply With Quote
 
 
 
 
Jorgen Grahn
Guest
Posts: n/a
 
      02-21-2013
On Thu, 2013-02-21, Maciej Labanowicz wrote:
....
> Another example of the redundant code is the
> initialization of 'result' in function 'fun'.
> But this is also a style that I prefer.
> Any variable should be initialized at begining.


Argh! A lot of people seem to do it, but I really dislike that
practice.

> For example, a someone has fixed this code with:
> if (foo_ptr) {
> result = &(foo_ptr->bar);
> }
> then function is still correctly working.


> In case the initialization is redundant then
> an optimizer will remove the code during compilation process.
> It is very hard to diagnose bugs that depends on the uninitialized
> variable, especially
> if it occures only ones per a week and only on client side (taken from
> real life).


Three things:

- Like others noted, modern compilers emit warnings about
uninitialized variables being used. That way you don't have to
clutter your code with 'int i = 0;', and in a sense squeeze more
information into your code: when you see 'int i;' but no warning,
you know[1] i will get a value later, in all relevant code paths.

'int i=0;' on the other hand may mean that 0 is a true
initialization value -- or just a dummy.

- The initializion technique you describe doesn't help avoid bugs;
it helps hiding bugs by making their symptoms more subtle.

What actually happens is that person A chooses a 'safe' initial
value, and person B creates the bug: uses the variable before its
/real/ initialization has been done. There are no guarantees that A
made the choice that matches B's assumptions.

Now you have a bug that neither the compiler nor tools like Valgrind
can detect: the program doesn't crash, it just produces results
which don't match the expected ones.

- All of this is less of a problem in C99, where you can usually
declare your variable where it's first used, i.e. where you know how
to initialize it. You should argue for C99 instead.

/Jorgen

[1] "Know" is too strong. If you call 'foo(&i)', the compiler cannot
generally know if foo() initializes i, and has to assume it does.

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
 
Reply With Quote
 
Maciej Labanowicz
Guest
Posts: n/a
 
      02-22-2013
On 21 Feb, 16:05, Shao Miller <(E-Mail Removed)> wrote:

> Can you explain this policy a bit more?
> Does the policy explain exactly when and where to add them?

In general it should be added only for clarification of the code.
Main requirements are confidential, so I can not share with you.

> Maybe that's why you are typing posts involving some of the subtleties
> of C? *So that you can fix a compiler that isn't good at warning about
> use of uninitialized objects? *I can think of a couple that do a pretty
> good job of it, but obviously that's not universal.

I agree that modern compilers are able to detect most of the problems.
It is great.

Example of the code that modern compiler
is silent about uninitialized variable:
$ gawk '{printf("%02u: %s\n", NR, $0);}' test.c
01: extern void bar(int *);
02: void foo(void) {
03: int x;
04: bar(&x);
05: }
$ gcc --version | head -n1
gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
$ gcc -W -Wall -ansi -pedantic -Werror -Wextra -Wuninitialized -
Wmissing-field-initializers -Wjump-misses-init -Winit-self -c test.c
$

If there is an -W option to GCC that detects the uninitialized
variable please give the info.

I don't want to convince anyone to use that 'style'.
I know that using it makes the life of programmer is easier in real
world.

Regards

--
Maciej Labanowicz
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      02-22-2013
Maciej Labanowicz <(E-Mail Removed)> writes:
[...]
> Example of the code that modern compiler
> is silent about uninitialized variable:
> $ gawk '{printf("%02u: %s\n", NR, $0);}' test.c
> 01: extern void bar(int *);
> 02: void foo(void) {
> 03: int x;
> 04: bar(&x);
> 05: }
> $ gcc --version | head -n1
> gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
> $ gcc -W -Wall -ansi -pedantic -Werror -Wextra -Wuninitialized -
> Wmissing-field-initializers -Wjump-misses-init -Winit-self -c test.c
> $
>
> If there is an -W option to GCC that detects the uninitialized
> variable please give the info.


"-O3" helps the compiler find some such issues, because of the
information collected during optimization, but there's no real
problem in this case.

There is no reference to the uninitialized *value* of x. If the
definition of bar is:

void bar(int *x) { *x = 42; }

then the code is perfectly legitimate.

Of course it's possible that bar could attempt to read the value of *x
before writing to it, and I don't know a way to make gcc warn about
that. Cross-function optimization is difficult; optimization across
translation units is even more so.

[...]

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Noob
Guest
Posts: n/a
 
      02-22-2013
Maciej Labanowicz wrote:

> Example of the code that modern compiler is silent about uninitialized variable:
> $ gawk '{printf("%02u: %s\n", NR, $0);}' test.c


For the sake of ZEUS! Please change %02u: to /*%02u:*/

> 01: extern void bar(int *);
> 02: void foo(void) {
> 03: int x;
> 04: bar(&x);
> 05: }
>
> If there is an option to GCC that detects the uninitialized
> variable please give the info.


NB: There is no error, at this point.
x must be initialized ONLY IF 'bar' expects it to be...

$ cat f1.c
extern void bar(int *p);
int main(void) { int x; bar(&x); return x; }
$ cat f2.c
void bar(int *p) { *p += 42; }
$ gcc -Wall -Wextra -O2 -flto f1.c f2.c
In file included from :0:0:
f1.c: In function ‘main’:
f2.c:1:23: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
f1.c:2:22: note: ‘x’ was declared here

http://gcc.gnu.org/wiki/LinkTimeOptimization

> --
> Maciej Labanowicz


NB: the "standard" signature delimiter is DASH DASH SPACE NEWLINE

 
Reply With Quote
 
Maciej Labanowicz
Guest
Posts: n/a
 
      02-22-2013
On 22 Feb, 17:46, Noob <r...@127.0.0.1> wrote:
> $ gcc -Wall -Wextra -O2 -flto f1.c f2.c


Nice to hear about that option.

Full example (more complicated):
--------------------------------
$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct {
int * p;
} strct;
void bar(strct * s) {
strct copy;
memcpy(&copy, s, sizeof (strct));
if (*copy.p < 1) {
*copy.p = 200;
}
else {
*copy.p = rand() % 200;
}
}
int foo(void) {
int x;
strct s;
s.p = &x;
bar(&s);
return (x > 50) && (x < 100);
}
int fill(void) {
int x = 10;
strct s;
s.p = &x;
bar(&s);
return 0;
}
int main(void) {
srand((unsigned)time(NULL));
fill();
if (foo()) {
printf("OK, HDD format has started.\n");
}
return EXIT_SUCCESS;
}
$ gcc -Wall -Wextra -O2 -flto main.c -o a.out
$ ./a.out
$
--------------------------------

I'm lucky guy, my HDD has been not formatted .

Regards

--
Maciej Labanowicz
"Project-Manager: (9 women) == (1 baby per month)"
 
Reply With Quote
 
Noob
Guest
Posts: n/a
 
      02-22-2013
Maciej Labanowicz wrote:

> "Project-Manager: (9 women) == (1 baby per month)"


WTF is that supposed to mean?

 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-22-2013
Noob <root@localhost> writes:

> Maciej Labanowicz wrote:
>
> > "Project-Manager: (9 women) == (1 baby per month)"

>
> WTF is that supposed to mean?


If 2 mean can dig one ditch in a week, how many men does it take
to dig the same ditch in an hour?

That question is really about the same, ie. applying purely
mathematical models to real-world problems, where practical
constraints must be observed. Google "Chinese horde debugging" and/or
read "The mythical man-month" for further enlightenment.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
 
 
Reply

Thread Tools

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 On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
Access from function in struct (pointer to function) to other items in the struct (advanced) Ole C Programming 4 10-26-2004 09:43 PM
sizeof(enum) == sizeof(int) ??? Derek C++ 7 10-14-2004 05:11 PM
Obtain sizeof struct element using offsetof()? Mark A. Odell C Programming 10 10-01-2004 01:24 AM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM



Advertisments