440,886 Members | 1,107 Online
Need help? Post your question and get tips & solutions from a community of 440,886 IT Pros & Developers. It's quick & easy.

# alignment when allocating an array of struct

 P: n/a Hello, I'm asking myself all kind of questions on allocating an array of struct with proper alignment. Is the following code oorrect ? I'm most interested by the statement t = malloc(n*sizeof(r)) and (to a degree) by the surrounding error checking. #include // a record of system-dependent size and alignment typedef struct r { char f0; long f1; char f2; } r; int main(int argc, char *argv[]) { long n; // number of elements to allocate r *t; // array of n records of type r if (argc==2 && // check argv[1] is our single parameter (n = atol(argv[1]))>0 && // convert to a positive number (size_t)(n*sizeof(r))/n==sizeof(r) && // check for size overflow // allocate n records of type r; is that OK ? (t = malloc(n*sizeof(r)))!=NULL) { // some use the array of n records long j; for(j=0;j
6 Replies

 P: n/a Francois Grieu wrote: Hello, I'm asking myself all kind of questions on allocating an array of struct with proper alignment. Is the following code oorrect ? I'm most interested by the statement t = malloc(n*sizeof(r)) and (to a degree) by the surrounding error checking. #include // a record of system-dependent size and alignment typedef struct r { char f0; long f1; char f2; } r; int main(int argc, char *argv[]) { long n; // number of elements to allocate r *t; // array of n records of type r if (argc==2 && // check argv[1] is our single parameter (n = atol(argv[1]))>0 && // convert to a positive number (size_t)(n*sizeof(r))/n==sizeof(r) && // check for size overflow // allocate n records of type r; is that OK ? (t = malloc(n*sizeof(r)))!=NULL) { // some use the array of n records long j; for(j=0;j

 P: n/a Francois Grieu wrote: On 4 jan, 19:32, Eric Sosman sizeof(r) must include whatever padding might be needed to makethe alignment work properly.It's not a matter of rounding up the result of sizeof; it's thatthe r instance contains its own padding and the padding countsas part of the sizeof an r. Ah... sizeof(r) itself is already properly rounded up. That's fine, and clears most of my concerns. But, just to be sure, how is that expressed in the (C89/90) standard ? I don't have either the original ANSI nor the first ISO version of the Standard handy, so I don't know. In N2794 (a pre-C99 draft; I've lost a disk and haven't retrieved my backup of the actual Standard yet), 6.5.3.4p3 says in part [...] When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding. Is there something wrong with my overflow test ? (size_t)(n*sizeof(r))/n==sizeof(r) Anything less contorted ? Since `n' is a signed long, this risks overflow with undefined behavior on machines where size_t promotes to long instead of the other way around. Try converting to size_t before multiplying, so the arithmetic is unsigned and "overflow" is well-behaved: ((size_t)n * sizeof(r)) / sizeof(r) == n This particular rearrangement works even when n==0, and it also catches negative n when size_t promotes to long. I think that it also catches negative n when long promotes to size_t, provided sizeof(r)>1. (Besides, dividing by a compile-time constant is likely to be faster than by a variable; just THINK of the nanoseconds you'll save! ;-) -- Er*********@sun.com Jan 4 '08 #3

 P: n/a Francois Grieu The compiler is right. r is a type name (an alias for atype name, actually), so writing `sizeof r' is like writing`sizeof int' -- and is equally wrong. Got it: sizeof variable is fine, sizeof type is wrong. Thanks for everything. Right. More generally, there are two forms of size expression: sizeof unary-expression sizeof ( type-name ) The unary-expression may be a variable name, but it doesn't have to be. For example, ``sizeof 42'' is equivalent to ``sizeof int''. (The use of "unary-expression" rather than "expression" means that, for example, ``sizeof 2 + 2'' doesn't apply the sizeof operator to ``2 + 2''; instead, it means ``(sizeof 2) + 2''. It's a way of expressing operator precedence.) -- Keith Thompson (The_Other_Keith) [...] "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Jan 5 '08 #4

 P: n/a In article <1199487009.440461@news1nwk>, Eric Sosman On 4 jan, 19:32, Eric Sosman >sizeof(r) must include whatever padding might be needed to makethe alignment work properly.It's not a matter of rounding up the result of sizeof; it's thatthe r instance contains its own padding and the padding countsas part of the sizeof an r. Ah... sizeof(r) itself is already properly rounded up. That's fine,and clears most of my concerns. But, just to be sure, how is thatexpressed in the (C89/90) standard ? I don't have either the original ANSI nor the first ISO version of the Standard handy, so I don't know. In N2794 (a pre-C99 draft; I've lost a disk and haven't retrieved my backup of the actual Standard yet), 6.5.3.4p3 says in part [...] When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding. I confirm this is also in ISO/IEC 9899:1999. >Is there something wrong with my overflow test ? (size_t)(n*sizeof(r))/n==sizeof(r)Anything less contorted ? Since `n' is a signed long, this risks overflow with undefined behavior on machines where size_t promotes to long instead of the other way around. Try converting to size_t before multiplying, so the arithmetic is unsigned and "overflow" is well-behaved: ((size_t)n * sizeof(r)) / sizeof(r) == n This particular rearrangement works even when n==0, and it also catches negative n when size_t promotes to long. I think that it also catches negative n when long promotes to size_t, provided sizeof(r)>1. (Besides, dividing by a compile-time constant is likely to be faster than by a variable; just THINK of the nanoseconds you'll save! ;-) Took me an iteration to realize that this works even if size_t is much smaller than long. Thanks! Francois Grieu Jan 7 '08 #5

 P: n/a On Fri, 04 Jan 2008 18:50:05 +0100, Francois Grieu wrote: >Hello, I'm asking myself all kind of questions on allocatingan array of struct with proper alignment.Is the following code oorrect ?I'm most interested by the statement t = malloc(n*sizeof(r))and (to a degree) by the surrounding error checking. #include // a record of system-dependent size and alignmenttypedef struct r { char f0; long f1; char f2; } r;int main(int argc, char *argv[]) { long n; // number of elements to allocate r *t; // array of n records of type r if (argc==2 && // check argv[1] is our single parameter (n = atol(argv[1]))>0 && // convert to a positive number atol is not a very good function for this purpose. Better to use strtol and take advantage of its error checking capabilities prior to using the result in the if. (size_t)(n*sizeof(r))/n==sizeof(r) && // check for size overflow What is the type of the product of a long and a size_t. Not just on your system but in general. If size_t is an unsigned int, I think the result would be a long and overflow could occur. Better to eliminate the possibility and move the cast inside the parentheses to get ((size_t)n*sizeof(r)) Even better still would be to change n to a size_t and use strtoul instead of strtol or atol above. // allocate n records of type r; is that OK ? (t = malloc(n*sizeof(r)))!=NULL) 1 - Your parentheses are unbalanced. You are missing a ). 2 - Wouldn't you like to be able to put out a different error message depending on whether argc was not 2 or malloc failed or ...? While the short-circuit mechanism inherent in && can make this complex if logically correct, it is a maintenance nightmare. { // some use the array of n records long j; for(j=0;jappropriately, and/or malloc guaranteed to return approriatelyaligned memory ? malloc and friends are also guaranteed to return an address properly aligned for any and every possible type of object, scalar or aggregate. >Is the calloc() library function guaranteed to perform somethingextra (beside zeroing the allocated memory) ? like, perhaps,rounding up the size passed, or checking that the product does On what basis would it round up more than the product? It has no idea what type of pointer you are assigning the resulting address to. >not overflow, or making extra alignment ? Since the alignment is guaranteed to be suitable for any type of object, what possible extra alignment is there? Since calloc allocates space for an array and size_t can hold the size of the largest possible array, I suggest that consistency demands that passing parameters to calloc where the product would exceed SIZE_MAX invokes undefined behavior >As an aside: one of my C compilers barks if I change sizeof(r)to sizeof r. Is this compiler defective ? No it is NOT C++. The parentheses are required unless the operand is an object. r is not an object. It is a typedef alias for struct r and both expressions are types, not objects. You could use *t with or without parentheses since *t is an object of type r. Any of your compilers that do not bark on sizeof r are broken. Remove del for email Jan 8 '08 #6

 P: n/a Barry Schwarz wrote: [...] >>As an aside: one of my C compilers barks if I change sizeof(r)to sizeof r. Is this compiler defective ? No it is NOT C++. The parentheses are required unless the operand is an object. r is not an object. It is a typedef alias for struct r and both expressions are types, not objects. You could use *t with or without parentheses since *t is an object of type r. Any of your compilers that do not bark on sizeof r are broken. Correction: the parentheses are required unless the operand is an expression. For example ``sizeof 42'' is valid. The operand of a sizeof operator is either an expression (specifically a "unary-expression") or a type name in parentheses. -- Keith Thompson (The_Other_Keith) [...] "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Jan 8 '08 #7

### This discussion thread is closed

Replies have been disabled for this discussion.