473,394 Members | 1,867 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Please help optimize (and standarize) this code...

Newbie-ish questions - I've been away from C for a _long_ time.

It seems to me that there ought to be easier (or at least shorter) ways
to do what this does. It does compile & run for me (with PowerC, a
16-bit DOS compiler); if there are nonstandard or "accidentally-works"
aspects, please let me know.

{This is the sort of situation where if I knew *what* to Google for, I
wouldn't *need* to... <grin>}

Code follows:

---------------------- snip ------------------------
#include <stdio.h>
#include <stdlib.h> /* for itoa */
#include <string.h> /* for memcpy(), strcpy(), strcat() */

#define NAMLEN 8
#define EXTLEN 3
#define MAX 512
#define MAXCOL 1

typedef struct {
char name[NAMLEN];
char ext[EXTLEN];
} NameExt;

NameExt NameArray[MAX+1];
int NameCnt=0;

main()
{
//...
char fmtstr[32], digits[12];
int i;
char NAM[NAMLEN+1], EXT[EXTLEN+1];
int colnum = 0;

//...
/* Fill the array with (test) names & extensions,
left-justified & space-filled (no (char)0's).
In the real app (...'d code), there's findfirst(),
findnext(), sorting, etc.*/

memcpy(&NameArray[0], "One 1 ", 11);
memcpy(&NameArray[1], "TwoTwoTw222", 11);
memcpy(&NameArray[2], "333 003", 11);
NameCnt = 3;
//...

/* Print names & extensions in multiple columns */

// Construct format string like "%8s%c%3s"
strcpy(fmtstr, "%");
strcat(fmtstr, itoa(NAMLEN, digits, 10));
strcat(fmtstr, "s%c%");
strcat(fmtstr, itoa(EXTLEN, digits, 10));
strcat(fmtstr, "s");

// Print according to the specified format
for(i=0; i<NameCnt; i++) {
memcpy(NAM, NameArray[i].name, NAMLEN);
NAM[NAMLEN] = (char)0;
memcpy(EXT, NameArray[i].ext, EXTLEN);
EXT[EXTLEN] = (char)0;
printf(fmtstr, NAM, '.', EXT);

// Handle columnizing here
if(colnum++ < MAXCOL) {
printf(" ");
} else {
printf("\n");
colnum = 0;
}
}
printf("\n");
//...
}
---------------------- snip ------------------------

Particularly, are there easier ways to:
(1) initialize the NameArray records;
(2) specify the format string, assuming I want to stick with constants
for the field widths; and
(3) printf the NameArray array-of-char fields without explicitly
converting them to strings?

Also, is there a way to get e.g.,
sizeof NameExt.Ext
(which doesn't work) at compile-time?

TIA!

Nov 14 '05 #1
39 2554
gtippery <gt******@altavista.net> wrote:
Newbie-ish questions - I've been away from C for a _long_ time. It seems to me that there ought to be easier (or at least shorter) ways
to do what this does. It does compile & run for me (with PowerC, a
16-bit DOS compiler); if there are nonstandard or "accidentally-works"
aspects, please let me know. {This is the sort of situation where if I knew *what* to Google for, I
wouldn't *need* to... <grin>} Code follows: ---------------------- snip ------------------------
#include <stdio.h>
#include <stdlib.h> /* for itoa */
Sorry, but itoa() is an extension that you won't always find in
<stdlib.h>.
#include <string.h> /* for memcpy(), strcpy(), strcat() */ #define NAMLEN 8
#define EXTLEN 3
#define MAX 512
#define MAXCOL 1 typedef struct {
char name[NAMLEN];
char ext[EXTLEN];
} NameExt; NameExt NameArray[MAX+1];
int NameCnt=0; main()
If you want to be sure that this also works with a C99 compiler you
must at least tell the compiler the return type of main() (which
must be int), since the old default assumption, that a function
without a declared return type will return int does not hold anymore.
Also telling the compiler the number of arguments is reasonable, so
you better make that either

int main( void )
or
int main( int argc, char *argv[ ] )
{
//...
char fmtstr[32], digits[12];
int i;
char NAM[NAMLEN+1], EXT[EXTLEN+1];
int colnum = 0; //...
/* Fill the array with (test) names & extensions,
left-justified & space-filled (no (char)0's).
In the real app (...'d code), there's findfirst(),
findnext(), sorting, etc.*/ memcpy(&NameArray[0], "One 1 ", 11);
This obviously assumes that the members of the NameExt structure are
packed, i.e. that the 'ext' member starts immediately after the 'name'
member without any padding in between. While you probably often will
get away with that it's not guaranteed to work since the compiler is
free to insert as many padding bytes between (and after) the members
as it likes. And if it does your scheme won't work anymore. So you
better make that

memcpy( &NameArray[0].name, "One ", NAMLEN );
memcpy( &NameArray[0].ext, "1 ", EXTLEN );
memcpy(&NameArray[1], "TwoTwoTw222", 11);
memcpy(&NameArray[2], "333 003", 11);
NameCnt = 3;
//... /* Print names & extensions in multiple columns */ // Construct format string like "%8s%c%3s"
strcpy(fmtstr, "%");
strcat(fmtstr, itoa(NAMLEN, digits, 10));
itoa() isn't a standard C function, so this will fail on systems
where there's no ito().
strcat(fmtstr, "s%c%");
strcat(fmtstr, itoa(EXTLEN, digits, 10));
strcat(fmtstr, "s");
Why don't you use sprintf() to make up the format string?

sprintf( fmtstr, "%%%ds%%c%%%ds" NAMLEN, EXTLEN );
// Print according to the specified format
for(i=0; i<NameCnt; i++) {
memcpy(NAM, NameArray[i].name, NAMLEN);
NAM[NAMLEN] = (char)0;
"(char)0" is probably better written as "'\0'", at least then all
C programmers with a bit of experience will know what you mean.
memcpy(EXT, NameArray[i].ext, EXTLEN);
EXT[EXTLEN] = (char)0;
printf(fmtstr, NAM, '.', EXT); // Handle columnizing here
if(colnum++ < MAXCOL) {
printf(" ");
} else {
printf("\n");
colnum = 0;
}
}
printf("\n");
//...
}
---------------------- snip ------------------------ Particularly, are there easier ways to:
(1) initialize the NameArray records;
Perhaps, but that will depend on what you want to initialize the array
elements with in the real case. Since I don't know what findfirst() and
findnext() return (they aren't standard C functions) it's impossible to
say if there's a simpler way to assign values to the structure members.
(2) specify the format string, assuming I want to stick with constants
for the field widths; and
(3) printf the NameArray array-of-char fields without explicitly
converting them to strings?
You actually don't have to do that since you specify the length of them,
so even without the terminating '\0' characters it will work correctly.
You can safely do

printf( fmtstr, NameArry[ 0 ].name, '.', NameArray[ 0 ].ext );

when 'fmtstr' is e.g. "%8s%c%3s".

BTW, an alternative would be to use

printf( "%*s%c%*s", NAMLEN, NameArray[ 0 ].name, '.',
EXTLEN, NameArray[ 0 ].ext );
or
printf( "%*s%c%*s", sizeof NameArray->name, NameArray[ 0 ].name, '.',
sizeof NameArray->ext, NameArray[ 0 ].ext );
Also, is there a way to get e.g.,
sizeof NameExt.Ext
(which doesn't work) at compile-time?


Yes, if you give sizeof the name of a real instance of the NameExt
struct, i.e.

sizeof NameArray[ 0 ].ext
or
sizeof NameArray->ext
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #2
Thanks for replying.

#include <stdlib.h> /* for itoa */
Sorry, but itoa() is an extension that you won't always find in
<stdlib.h>.


Yeah, I had to dig a bit to even find it, in my compiler's library -
I guess it was "depreciated" even in 1993...

main()

.... you better make that either

int main( void )
or
int main( int argc, char *argv[ ] )

Yup. I did that deliberately to provoke someone to answer.
<grin> That's gotta be either #1 or #2 on the 'most frequent"
list...

/* Fill the array with (test) names & extensions,
left-justified & space-filled (no (char)0's).
In the real app (...'d code), there's findfirst(),
findnext(), sorting, etc.*/
memcpy(&NameArray[0], "One 1 ", 11);

This obviously assumes that the members of the NameExt structure are
packed, i.e. that the 'ext' member starts immediately after the

'name' member without any padding in between. While you probably often will
get away with that it's not guaranteed to work since the compiler is
free to insert as many padding bytes between (and after) the members
as it likes. And if it does your scheme won't work anymore. So you
better make that

memcpy( &NameArray[0].name, "One ", NAMLEN );
memcpy( &NameArray[0].ext, "1 ", EXTLEN );

A good point, and exactly the sort of thing I wanted to know.

// Construct format string like "%8s%c%3s"
strcpy(fmtstr, "%");
strcat(fmtstr, itoa(NAMLEN, digits, 10)); itoa() isn't a standard C function, so this will fail on systems
where there's no itoa().
Do you suggest sprintf(), or is there a standard, specific
integer-to-characters function? BTW, do you know if itoa()
[or something equivalent] is not standardized because character
sets aren't, or is there some other reason?

strcat(fmtstr, "s%c%");
strcat(fmtstr, itoa(EXTLEN, digits, 10));
strcat(fmtstr, "s");

Why don't you use sprintf() to make up the format string?

sprintf( fmtstr, "%%%ds%%c%%%ds" NAMLEN, EXTLEN );


Argh! Because it didn't occur to me. I _did_ consider using
sprintf() to format the entire output line, but not just the
format string.

// Print according to the specified format
for(i=0; i<NameCnt; i++) {
memcpy(NAM, NameArray[i].name, NAMLEN);
NAM[NAMLEN] = (char)0;

"(char)0" is probably better written as "'\0'", at least then all
C programmers with a bit of experience will know what you mean.


I _knew_ there was a simpler way than (char)0, but while my
compiler accepts charvar = 0x00 and charvar = \0, neither looked
"explicit" enought. I guess I'd forgotten you could use escaped
characters in '' constants like you can in "" constants.

Particularly, are there easier ways to:
(1) initialize the NameArray records;
[Your corrected version requoted here for reference:]
memcpy( &NameArray[0].name, "One ", NAMLEN );
memcpy( &NameArray[0].ext, "1 ", EXTLEN );

Perhaps, but that will depend on what you want to initialize the array elements with in the real case.
Well, for illustration purposes, is there a better way to do
what it _does_ do (setting an array-of-char field of a
structure to a text constant) than using memcpy()?

Since I don't know what findfirst() and
findnext() return (they aren't standard C functions)
They're MS-DOS functions; in my library they return a pointer to
a structure full of binary values for file size, dates, etc.

What's the standard-C way to get the contents of a directory? I
have a few C reference books, but they date from the 1980's.
(And I wasn't around them when I originally posted.)
(2) specify the format string, assuming I want to stick with
constants for the field widths; and
(3) printf the NameArray array-of-char fields without explicitly
converting them to strings?

You actually don't have to do that since you specify the length of

them, so even without the terminating '\0' characters it will work correctly. You can safely do

printf( fmtstr, NameArry[ 0 ].name, '.', NameArray[ 0 ].ext );

when 'fmtstr' is e.g. "%8s%c%3s".
I attempted something like that - I originally wrote "%8c%c%3c",
but then realized that wouldn't do what I wanted, and

printf("%c%c%c%c%c%c%c%c%c%c%c%c",
NameArray[i].name[0],
NameArray[i].name[1],
...
NameArray[i].ext[2]);
was just "over the top". <grin> C doesn't have anything like
FORTRAN's "implicit DO" does it?

I wasn't sure "%8s" was safe, 'though I can't remember now why I
thought it might not be.

BTW, an alternative would be to use

printf( "%*s%c%*s", NAMLEN, NameArray[ 0 ].name, '.',
EXTLEN, NameArray[ 0 ].ext );
or
printf( "%*s%c%*s", sizeof NameArray->name, NameArray[ 0 ].name, '.', sizeof NameArray->ext, NameArray[ 0 ].ext );

Ah, "%*", _that's_ what I couldn't think of.

Also, is there a way to get e.g.,
sizeof NameExt.Ext
(which doesn't work) at compile-time?

Yes, if you give sizeof the name of a real instance of the NameExt
struct, i.e.

sizeof NameArray[ 0 ].ext
or
sizeof NameArray->ext


OK, I need to have that explained a bit more. Why does
sizeof(int) work? It's not a "real instance". Is that the
sizeof paren/no paren thing?

Why does NameArray->ext work, without a specific array index?

And I'm definitely confused by NameArray.ext, *NameArray.ext [or
is that *(NameArray).ext?], and NameArray->ext. Could you kindly
explain the differences? I know an array reference is (almost?)
a pointer, but I don't know for structs.

Thanks.

--
{ Don't use the "altavista.net" reply-to; it's extinct, but I don't
know how to change it in Google Groups. Use "comcast" instead of
"altavista" if you want to email me. }

Nov 14 '05 #3
gtippery <gt******@altavista.net> wrote:
#include <stdlib.h> /* for itoa */
Sorry, but itoa() is an extension that you won't always find in
<stdlib.h>. Yeah, I had to dig a bit to even find it, in my compiler's library -
I guess it was "depreciated" even in 1993...
It wasn't deprecated because it never was part of the set of functions
the standard requires.
main()

...
you better make that either

int main( void )
or
int main( int argc, char *argv[ ] )

Yup. I did that deliberately to provoke someone to answer.
<grin> That's gotta be either #1 or #2 on the 'most frequent"
list...


You don't seem to have too good an opinion about clc;-)
itoa() isn't a standard C function, so this will fail on systems
where there's no itoa(). Do you suggest sprintf(), or is there a standard, specific
integer-to-characters function? BTW, do you know if itoa()
[or something equivalent] is not standardized because character
sets aren't, or is there some other reason?
I don't know what itoa() would be good for since it only reproduces
a functionality you already have with sprintf(). I guess someone
invented it for symmetry reasons because there's atoi(), But atoi()
is a rather useless function anyway and should be avoided in favour
of strtol().
Particularly, are there easier ways to:
(1) initialize the NameArray records; [Your corrected version requoted here for reference:]
memcpy( &NameArray[0].name, "One ", NAMLEN );
memcpy( &NameArray[0].ext, "1 ", EXTLEN ); Perhaps, but that will depend on what you want to initialize the
array elements with in the real case. Well, for illustration purposes, is there a better way to do
what it _does_ do (setting an array-of-char field of a
structure to a text constant) than using memcpy()?
I don't see any better way here.
Since I don't know what findfirst() and
findnext() return (they aren't standard C functions)

They're MS-DOS functions; in my library they return a pointer to
a structure full of binary values for file size, dates, etc. What's the standard-C way to get the contents of a directory? I
have a few C reference books, but they date from the 1980's.
(And I wasn't around them when I originally posted.)
There aren't any standard C functions, you must use the extensions
for your OS - the word "directory" doesn't even appear anywhere in
the C standard.
Also, is there a way to get e.g.,
sizeof NameExt.Ext
(which doesn't work) at compile-time?

Yes, if you give sizeof the name of a real instance of the NameExt
struct, i.e.

sizeof NameArray[ 0 ].ext
or
sizeof NameArray->ext

OK, I need to have that explained a bit more. Why does
sizeof(int) work? It's not a "real instance". Is that the
sizeof paren/no paren thing?
Yes, it is. Without the parentheses you can only use names of
variables. If you want to use types they must be enclosed in
parenthesis.
Why does NameArray->ext work, without a specific array index?
Because NameArray is automatically taken here to be a pointer to
the first element of the NameArray array (like when you pass an
array to a function).
And I'm definitely confused by NameArray.ext, *NameArray.ext [or
is that *(NameArray).ext?], and NameArray->ext.
When you have an array of structures like

struct xyz {
int x;
char y;
}

struct xyz a[ 10 ];

then 'a' "decays" in situations where it's used as a value into a
pointer to the first element of the array. Thus 'a->y' is the same
as 'a[0].y' (as is '(*a).y').
I know an array reference is (almost?) a pointer, but I don't know
for structs.


It doesn't matter if you have an array of ints or structures or unions
or function pointers or whatever, it's always the same. When the name
of an array is used in a situation where it's used as if had a value
(like in 'a->y') then it automatically is converted to a pointer to
the first element of the array, no matter what kind of elements the
array has. See also what Chris Torek calls "The Rule":

http://web.torek.net/torek/c/index.html

Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #4

Je***********@physik.fu-berlin.de wrote:

gtippery <gtipp...@altavista.net> wrote:
#include <stdlib.h> /* for itoa */ Sorry, but itoa() is an extension that you won't always find in
<stdlib.h>. Yeah, I had to dig a bit to even find it, in my compiler's library -
I guess it was "depreciated" even in 1993...


It wasn't deprecated because it never was part of the set of

functions the standard requires.
I meant "depreciated" by the distributor of the library; hence the
quotes.

I don't know what itoa() would be good for since it only reproduces
a functionality you already have with sprintf(). I guess someone
invented it for symmetry reasons because there's atoi(), But atoi()
is a rather useless function anyway and should be avoided in favour
of strtol().

Most of the C library "reproduces a functionality you already have",
but hopefully in a more convenient form. itoa()'s more convenient in
an
expression.

Also, is there a way to get e.g.,
sizeof NameExt.Ext
(which doesn't work) at compile-time?

(Requoting for context:)

#define NAMLEN 8
#define EXTLEN 3
#define MAX 512

typedef struct {
char name[NAMLEN];
char ext[EXTLEN];
} NameExt;

NameExt NameArray[MAX+1];
int NameCnt=0;
Yes, if you give sizeof the name of a real instance of the NameExt
struct, i.e. sizeof NameArray[ 0 ].ext
or
sizeof NameArray->ext
OK, I need to have that explained a bit more. Why does
sizeof(int) work? It's not a "real instance". Is that the
sizeof paren/no paren thing?

Yes, it is. Without the parentheses you can only use names of
variables. If you want to use types they must be enclosed in
parenthesis.

But 'sizeof(NameExt.Ext)' doesn't work either. Is NameExt.Ext a
type, or what is it? It's certainly not a variable.
And I'm definitely confused by NameArray.ext, *NameArray.ext [or
is that *(NameArray).ext?], and NameArray->ext.

When you have an array of structures like

struct xyz {
int x;
char y;
}

struct xyz a[ 10 ];

then 'a' "decays" in situations where it's used as a value into a
pointer to the first element of the array. Thus 'a->y' is the same
as 'a[0].y' (as is '(*a).y').


What (if anything) would 'a.y' be?

I know an array reference is (almost?) a pointer, but I don't know
for structs.


It doesn't matter if you have an array of ints or structures or

unions or function pointers or whatever, it's always the same. When the name of an array is used in a situation where it's used as if had a value
(like in 'a->y') then it automatically is converted to a pointer to
the first element of the array, no matter what kind of elements the
array has. See also what Chris Torek calls "The Rule":

http://web.torek.net/torek/c/index.html


I didn't mean "for an array of structs", I meant "for structs", i.e.,
in your example, is a reference to xyz (ever?) a pointer? From reading
Torek's essay you pointed to, it appears it is not.

Speaking of that essay, I'm still trying to digest it. Part of my
problem is difficulty understanding C declarations, but I'm working
on it.

Nov 14 '05 #5
gtippery <gt******@altavista.net> wrote:
> Also, is there a way to get e.g.,
> sizeof NameExt.Ext
> (which doesn't work) at compile-time?
(Requoting for context:) #define NAMLEN 8
#define EXTLEN 3
#define MAX 512 typedef struct {
char name[NAMLEN];
char ext[EXTLEN];
} NameExt; NameExt NameArray[MAX+1];
int NameCnt=0; Yes, if you give sizeof the name of a real instance of the NameExt
struct, i.e.

sizeof NameArray[ 0 ].ext
or
sizeof NameArray->ext

OK, I need to have that explained a bit more. Why does
sizeof(int) work? It's not a "real instance". Is that the
sizeof paren/no paren thing?


Yes, it is. Without the parentheses you can only use names of
variables. If you want to use types they must be enclosed in
parenthesis.


But 'sizeof(NameExt.Ext)' doesn't work either. Is NameExt.Ext a
type, or what is it? It's certainly not a variable.


There are two things here. First of all there's nothing called
"NameExt.Ext" at all, I guess you mean "NameExt.ext" but since
you use the wrong spelling consistendly I am wondering. Second,
and more important, "NameExt.ext" is neither a variable nor a
type. The names of the elements of a structure aren't types but
they are also not variables. So neither 'sizeof NameExt.ext' nor
'sizeof(NameExt.ext)' can work. Therefore you're here forced to
use a real instance of the structure to get at the size of its
elements - at least I don't see any other way at the moment.
When you have an array of structures like

struct xyz {
int x;
char y;
}

struct xyz a[ 10 ];

then 'a' "decays" in situations where it's used as a value into a
pointer to the first element of the array. Thus 'a->y' is the same
as 'a[0].y' (as is '(*a).y').

What (if anything) would 'a.y' be?


That wouldn't make sense since 'a' isn't a structure (or union)
but, when used in value context like here, a pointer to the first
element of the array. And then the dot can't be used since a dot
is only allowed after a structure (or union) variable name.
I know an array reference is (almost?) a pointer, but I don't know
for structs.


It doesn't matter if you have an array of ints or structures or

unions
or function pointers or whatever, it's always the same. When the name of an array is used in a situation where it's used as if had a value
(like in 'a->y') then it automatically is converted to a pointer to
the first element of the array, no matter what kind of elements the
array has. See also what Chris Torek calls "The Rule":

http://web.torek.net/torek/c/index.html

I didn't mean "for an array of structs", I meant "for structs", i.e.,
in your example, is a reference to xyz (ever?) a pointer? From reading
Torek's essay you pointed to, it appears it is not.


Yes, in contrast to arrays, structures are "first class citizens" in C,
so if you have the name of a structure variable without any adornments
it means the whole structure and it's not converted to a pointer to
the structure. So for something like

struct xyz b;
struct xyz a[10];
some_func( b, a );

'b' gets passed by value, i.e. a copy of the structure is passed to
the function as with the basic types like ints etc., while for the
array 'a' only a pointer to the array is what the function receives.
And you can copy structures as a whole like in

struct xyz b = { 42, 'a' };
struct xyz c;
c = b;

which is something you also can't do with arrays.

Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #6
[Here is one of those older articles I was saving for a followup,
found via references: lines in newer postings.]
gtippery <gt******@altavista.net> wrote:
(3) printf the NameArray array-of-char fields without explicitly
converting them to strings?

In article <37*************@uni-berlin.de>
<Je***********@physik.fu-berlin.de> wrote:You actually don't have to do that since you specify the length of them,
so even without the terminating '\0' characters it will work correctly.
You can safely do

printf( fmtstr, NameArry[ 0 ].name, '.', NameArray[ 0 ].ext );

when 'fmtstr' is e.g. "%8s%c%3s".
This is almost, but not quite, right: you need "%.8s" to tell
printf() that the corresponding "char *" value points to (the first
element of) an array of size 8. "%8s" means "points to a \0-terminated
string as usual, but print it in a field at least 8 characters
wide":

printf("%s.%s\n", "file", "c");

prints "file.c\n", but:

printf("%8s.%3s\n", "file", "c");

prints " file. c\n". To get the blank-padding on the left, use
the '-' flag:

printf("%-8s.%-3s\n", "file", "c");

prints "file .c \n".

Of course, you can combine these, e.g.:

printf("%-8.8s%c%-3.3s", name, '.', ext);

would work.
BTW, an alternative would be to use

printf( "%*s%c%*s", NAMLEN, NameArray[ 0 ].name, '.',
EXTLEN, NameArray[ 0 ].ext );
or
printf( "%*s%c%*s", sizeof NameArray->name, NameArray[ 0 ].name, '.',
sizeof NameArray->ext, NameArray[ 0 ].ext );


Nit: "sizeof" produces a size_t value, but "%*" (and "%.*") require
an int. Since printf() is variadic, a cast is appropriate here:

printf("%.*s%c%.*s",
(int)sizeof NameArray->name, NameArray[0].name, '.',
(int)sizeof NameArray->ext, NameArray[0].ext);

or:

printf("%-*.*s%c%-*.*s",
(int)sizeof NameArray->name, (int)sizeof NameArray->name,
NameArray[0].name, '.',
(int)sizeof NameArray->ext, (int)sizeof NameArray->ext,
NameArray[0].ext);

for instance. (I prefer the version with the NAMLEN and EXTLEN
"#define"s, myself. Fewer casts make me happier. :-) )
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #7
I think you guys are scaring me. I'm half-expecting Brian or Dennis to
chime in next with a correction to the correction to the corrections,
and it appears I'm going to have to expand my vocabulary as well as my
C skills.

BTW, thanks for not asking, but yes, I *can* spell "standardize".
<grin> Can I change the header without breaking the thread?

Nov 14 '05 #8

Dave Thompson wrote:
On 21 Feb 2005 12:27:37 GMT, Je***********@physik.fu-berlin.de wrote:
.... Aside from Jens' suggestion of sprintf (fmtstr, "%%%ds", NAMLEN) etc., IF your lengths are #define'd as only an unsigned decimal literal --
not anything else like say #define NAMLEN (128/16) -- you can
stringize them into a constant string:
#define XSTR(x) XSTR2(x) /* indirection to expand macro as arg */
#define XSTR2(x) #x
char fmtstr [] = "%" XSTR(NAMLEN) "s"; /* etc. */


I see how this is supposed to work, but not how it gets there with the
indirection. Could you show me step by step how that expands, or
possibly direct me to a good explanation of stringizing and pasting in
macros? I've read about the "#" but didn't understand it.

printf( "%*s%c%*s", sizeof NameArray->name, NameArray[ 0 ].name, '.', sizeof NameArray->ext, NameArray[ 0 ].ext );

Agree the first, but in the second the type of sizeof foo is size_t
not int, and may not work correctly as a vararg. Cast it.

Also I would write both the sizeof operand and the by-value argument
as array[i].name for clarity -- -> is equvalent to [0]. but when
reading it wastes time to verify it was used correctly in this case.


By "correctly" do you just mean that it refers to the same thing as the
by-value argument, or some other sort of correctness?

Nov 14 '05 #9

With thanks to Jens, Chris, and David, here's the revised version.
Besides recoding to the standard and simplifying, I attempted to
make capitalization more consistent and MAXCOL a bit more obvious.
I think it looks a lot better now. Does anything else need changing?
#include <stdio.h>
#include <string.h> /* for memcpy() */
#define NAMLEN 8
#define EXTLEN 3
#define MAX 512
#define MAXCOL 2
typedef struct {
char name[NAMLEN];
char ext[EXTLEN];
} NameExt;
NameExt nameArray[MAX+1];
int nameCnt=0;
int main(void)
{

int i;
int colnum = 0;
/* Fill the array with (test) names & extensions,
left-justified & space-filled (no '\0' characters). */

memcpy( &nameArray[0].name, "One ", NAMLEN );
memcpy( &nameArray[0].ext, "1 ", EXTLEN );

memcpy( &nameArray[1].name, "TwoTwoTw", NAMLEN );
memcpy( &nameArray[1].ext, "222", EXTLEN );

memcpy( &nameArray[2].name, "333 ", NAMLEN );
memcpy( &nameArray[2].ext, "003", EXTLEN );

nameCnt = 3;
/* Print names & extensions in multiple columns */

for(i=0; i<nameCnt; i++) {
printf("%-*.*s.%-*.*s",
NAMLEN, NAMLEN, nameArray[i].name,
EXTLEN, EXTLEN, nameArray[i].ext);

/* Handle columnizing here */
if(++colnum < MAXCOL) {
printf(" ");
} else {
printf("\n");
colnum = 0;
}
}
printf("\n");

}
Two questions:

1) Should I use a cast to (size_t) on the third parameter of the
memcopy()'s? Does memcpy()'s prototype take care of that?

2) Would

"%-*.*s" "." "%-*.*s"

be easier to read than

"%-*.*s.%-*.*s"

as the printf() format string?

Nov 14 '05 #10
gtippery wrote:
Dave Thompson wrote:
On 21 Feb 2005 12:27:37 GMT, Je***********@physik.fu-berlin.de wrote:


...
Aside from Jens' suggestion of sprintf (fmtstr, "%%%ds", NAMLEN)


etc.,
IF your lengths are #define'd as only an unsigned decimal literal --
not anything else like say #define NAMLEN (128/16) -- you can
stringize them into a constant string:
#define XSTR(x) XSTR2(x) /* indirection to expand macro as arg */
#define XSTR2(x) #x
char fmtstr [] = "%" XSTR(NAMLEN) "s"; /* etc. */

I see how this is supposed to work, but not how it gets there with the
indirection. Could you show me step by step how that expands, or
possibly direct me to a good explanation of stringizing and pasting in
macros? I've read about the "#" but didn't understand it.


#x puts quotation marks around whatever x is:

XSTR2(NAMLEN) gives you "NAMLEN".
With #define NAMLEN 42,
XSTR(NAMLEN) gives you XSTR2(42), i.e. "42"
fmtstr thus becomes "%" "42" "s", equivalent to "%42s"
printf( "%*s%c%*s", sizeof NameArray->name, NameArray[ 0
].name, '.',
sizeof NameArray->ext, NameArray[ 0 ].ext


);
Agree the first, but in the second the type of sizeof foo is size_t
not int, and may not work correctly as a vararg. Cast it.

Also I would write both the sizeof operand and the by-value argument
as array[i].name for clarity -- -> is equvalent to [0]. but when
reading it wastes time to verify it was used correctly in this case.


By "correctly" do you just mean that it refers to the same thing as the
by-value argument, or some other sort of correctness?


IMO, you are referring to the second "correctly".
If you see
"*s", (int) sizeof array[i].name, array[i].name
you know that the field width and the string fit together whereas
"*s", (int) sizeof array->name, array[i].name
makes you think for a moment whether this is correct.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #11
gtippery wrote:
Newbie-ish questions - I've been away from C for a _long_ time.

It seems to me that there ought to be easier (or at least shorter) ways to do what this does.


<large snip>

Well, here's something shorter and more similar to what you'd encounter
in practice. For something like this, not many people are going to
#define the size of the members of struct NameExt, since you can get at
them with sizeof. Also, many times people are going to use a sentinel
value to signal the end of the array rather than maintain a separate
variable to do so.

"(i + 1) % MAXCOL" is marginally idiomatic for producing columned
output in situations where MAXCOL is a power of two or "small enough"
for the compiler to play fancy tricks with.
---snip---
#include <stdio.h>

#define MAXCOL 2

struct NameExt
{
char name[9];
char ext[4];
};
int main(void)
{
/* Note sentinel at end */
struct NameExt list[] = {
{ "BillyBob", "123" },
{ "Steve", "456" },
{ "Tom", "789" },
{ "Joe", "012" },
{ "Sal", "345" },
{ "", "" },
};

/* Print the array out */
size_t i;
for(i = 0; *list[i].name; i++)
printf("%-*s%-*s%s",
sizeof(list[i].name), list[i].name,
sizeof(list[i].ext), list[i].ext,
(i + 1) % MAXCOL ? "" : "\n");

return 0;
}
---snip---

[mark@icepick ~]$ gcc -Wall -O2 -ansi -pedantic foo.c -o foo
[mark@icepick ~]$ ./foo
BillyBob 123 Steve 456
Tom 789 Joe 012
Sal 345
[mark@icepick ~]$
Mark F. Haigh
mf*****@sbcglobal.net

Nov 14 '05 #12
Mark F. Haigh wrote:
Well, here's something shorter and more similar to what you'd encounter in practice. For something like this, not many people are going to
#define the size of the members of struct NameExt, since you can get at them with sizeof. Also, many times people are going to use a sentinel value to signal the end of the array rather than maintain a separate
variable to do so.

I don't see any particular advantage either way on either of these
changes:
-- See an earlier posting for another opinion on #define's vs.
casting sizeof's to int's for printf; and there may be other places
that need to use the values.
-- A sentinel's easier if you're using pointers (or doing
comparisons), but what's its advantage if you're indexing? And that's
assuming the count's not needed for anything else, of course.
"(i + 1) % MAXCOL" is marginally idiomatic for producing columned
output in situations where MAXCOL is a power of two or "small enough"
for the compiler to play fancy tricks with.

What kind of "tricks" did you have in mind that the compiler might do
with, say, 5 columns per line? Isn't it either going to have to divide
or to maintain an internal modulo counter (like I'm doing explicitly)?

I used a separate column counter have the column # directly available
for other purposes (not shown) and debugging. Also, there are
additional fields in each column in the working program, so putting the
column logic separately seemed easier. I _will_ see if I can use the
%s / ? combo.

The rest of your code doesn't quite do the same thing as mine - the
"input" data's formatted differently and so's the output.

If you just wanted to show something similar, that's fine, and it was
interesting. But the reason I didn't use an array of strings in the
first place is that in the real program, the data's coming from an
existing packed data structure in memory (returned by the OS), and
would have to be converted to strings to use your sentinel and printing
techniques; so as far as I can see I'd need the memcpy()'s anyway.

Then to get the right output, it needs the changes I show below to
allow for the fact that the structure members now each include '\0'.
Also, the array's larger now (by two bytes per element), but that won't
actually be a problem in my case.

---snip---
#include <stdio.h>

#define MAXCOL 2

struct NameExt
{
char name[9];
char ext[4];
};
int main(void)
{
/* Note sentinel at end */
struct NameExt list[] = {
{ "BillyBob", "123" },
{ "Steve", "456" },
{ "Tom", "789" },
{ "Joe", "012" },
{ "Sal", "345" },
{ "", "" },
};

/* Print the array out */
size_t i;
What's the reason for using size_t instead of just int? I don't see
anywhere you use i as a size.
for(i = 0; *list[i].name; i++)
*list[i].name is the same as list[i].name[0], right? You're checking
if the first char is zero?
printf("%-*s%-*s%s",
printf("%-*s.%-*s%s",
sizeof(list[i].name), list[i].name,
sizeof(list[i].ext), list[i].ext,
(int)sizeof(list[i].name) - 1, list[i].name,
(int)sizeof(list[i].ext) - 1, list[i].ext,
(i + 1) % MAXCOL ? "" : "\n");
(i + 1) % MAXCOL ? " " : "\n");

return 0;
I've been meaning to ask about that. Older references seem to imply
that main() defaults to returning 0, and I haven't seen anything newer
that says differently, but I wouldn't be surprised. I downloaded a
copy of a "late draft" of the spec, but it was a .bz and I couldn't
open it. 8(
}
---snip---

[mark@icepick ~]$ gcc -Wall -O2 -ansi -pedantic foo.c -o foo
[mark@icepick ~]$ ./foo
BillyBob 123 Steve 456
Tom 789 Joe 012
Sal 345
[mark@icepick ~]$

Should look like this:

BillyBob.123 Steve .456
Tom .789 Joe .012
Sal .345

Mark F. Haigh
mf*****@sbcglobal.net


Nov 14 '05 #13

Michael Mair wrote:
....
#x puts quotation marks around whatever x is:

XSTR2(NAMLEN) gives you "NAMLEN".
With #define NAMLEN 42,
XSTR(NAMLEN) gives you XSTR2(42), i.e. "42"
fmtstr thus becomes "%" "42" "s", equivalent to "%42s"

OK, thanks. Is the indirection necessary to avoid getting a literal
"#" instead?

....
Agree the first, but in the second the type of sizeof foo is size_t
not int, and may not work correctly as a vararg. Cast it.

Also I would write both the sizeof operand and the by-value argumentas array[i].name for clarity -- -> is equvalent to [0]. but when
reading it wastes time to verify it was used correctly in this
case.
By "correctly" do you just mean that it refers to the same thing as the by-value argument, or some other sort of correctness?


IMO, you are referring to the second "correctly".


Yes. Sorry for the ambiguity.
If you see
"*s", (int) sizeof array[i].name, array[i].name
you know that the field width and the string fit together whereas
"*s", (int) sizeof array->name, array[i].name
makes you think for a moment whether this is correct.


Thanks, that's what I thought.

Nov 14 '05 #14
gtippery wrote:
Mark F. Haigh wrote:

<large snip>
If you just wanted to show something similar, that's fine, and it was
interesting. But the reason I didn't use an array of strings in the
first place is that in the real program, the data's coming from an
existing packed data structure in memory (returned by the OS), and
would have to be converted to strings to use your sentinel and printing techniques; so as far as I can see I'd need the memcpy()'s anyway.


And how was I supposed to know this? State this up front next time.
I'd thought it was for some kind of class project (first name / 3 digit
telephone extension), and that you had poor taste in data structures
and compilers.

I'll take another look when I get some time. Disregard the previous
post, and note:

1. Yes, you should cast size_t to int if it's going to be going
through the default argument promotions. I shouldn't have posted so
hastily right before bedtime (on some days, my only time for c.l.c).
Shame on me.

2. There are all kinds of dirty tricks and pre-canned "divide by x"
code sequences for compiler writers. Look at "Hacker's Delight" by
Henry S. Warren Jr. for more info on some interesting tricks (magic
numbers, etc).

3. What's the biggest number of elements that your array can have?
Check your platform docs. It may be more than int can handle, but less
than or equal to what size_t can handle.

4. Always put a return statement in main. It's necessary in C89, and
good style in C99.
Mark F. Haigh
mf*****@sbcglobal.net

Nov 14 '05 #15
gtippery wrote:
.... snip ...
I've been meaning to ask about that. Older references seem to imply
that main() defaults to returning 0, and I haven't seen anything newer
that says differently, but I wouldn't be surprised. I downloaded a
copy of a "late draft" of the spec, but it was a .bz and I couldn't
open it. 8(


Sounds like you got it from me. You just have to feed it to bzip2
to expand it. Execute "bzip2 -dc n869_txt.bz2" and n869.txt will
magically appear. However you got it over a 56k modem in about 2
minutes instead of about 9 minutes, due to the compressions. A zip
version would have taken about 3 minutes.

Google for bzip2, and keep it available. You can find it for most
systems.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #16

CBFalconer wrote:
gtippery wrote:
... snip ...
I downloaded a
copy of a "late draft" of the spec, but it was a .bz and I couldn't
open it. 8(


Sounds like you got it from me.


Yup. Lots of other interesting stuff you have there, btw. I'm going
to dig throught that Borland/ISO-input thing when I can.
You just have to feed it to bzip2
to expand it. Execute "bzip2 -dc n869_txt.bz2" and n869.txt will
magically appear. However you got it over a 56k modem in about 2
minutes instead of about 9 minutes, due to the compressions. A zip
version would have taken about 3 minutes.


Well, actually I got it in about 5 seconds (cable modem). Guess it
saved me, oh, maybe 1 or 2 seconds vs. zip... <grin>

Nov 14 '05 #17
gtippery wrote:
Michael Mair wrote:
...
#x puts quotation marks around whatever x is:

XSTR2(NAMLEN) gives you "NAMLEN".
With #define NAMLEN 42,
XSTR(NAMLEN) gives you XSTR2(42), i.e. "42"
fmtstr thus becomes "%" "42" "s", equivalent to "%42s"


OK, thanks. Is the indirection necessary to avoid getting a literal
"#" instead?


[For the record, I quote the definitions of XSTR and XSTR2:
#define XSTR(x) XSTR2(x) /* indirection to expand macro as arg */
#define XSTR2(x) #x
]

Nope. Have a look at the direct call to XSTR2:
XSTR2(42) gives you "42", as expected
but
XSTR2(SOME_MACRO_EXPRESSION) gives you "SOME_MACRO_EXPRESSION"
instead of whatever SOME_MACRO_EXPRESSION expands to. In the
above case, in order to get the 42 "out of" NAMLEN, we need the
indirection. XSTR(NAMLEN) expands NAMLEN (to 42) before
XSTR2(expansion of NAMLEN) is applied. Thus, XSTR(NAMLEN) gives
you "42".
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #18

Mark F. Haigh wrote:
gtippery wrote:
Mark F. Haigh wrote:

<large snip>
If you just wanted to show something similar, that's fine, and it was interesting. But the reason I didn't use an array of strings in the first place is that in the real program, the data's coming from an
existing packed data structure in memory (returned by the OS), and
would have to be converted to strings to use your sentinel and

printing
techniques; so as far as I can see I'd need the memcpy()'s anyway.


And how was I supposed to know this? State this up front next time.


The "real app" is mentioned in the original post (in a comment).
Anyway, I wasn't objecting, just explaining.
I'd thought it was for some kind of class project (first name / 3 digit telephone extension), and that you had poor taste in data structures
and compilers.
Well, "de gustibus non est disputandum", and I've no reason to think
mine's particularly good. The compiler choice is partially dictated by
the target system, which runs PC-DOS 6. I've also got Borland's
compiler, but it seemed like overkill. PowerC, as far as I've seen to
date, has all the C89 features except localization (if that's strictly
C89). It may not be "picky" enough -- I need to check the options in
the docs.
.... I'll take another look when I get some time. Disregard the previous
post, and note:

1. Yes, you should cast size_t to int if it's going to be going
through the default argument promotions.
I learned this from an earlier post in this same thread, myself.
2. There are all kinds of dirty tricks and pre-canned "divide by x"
code sequences for compiler writers. Look at "Hacker's Delight" by
Henry S. Warren Jr. for more info on some interesting tricks (magic
numbers, etc).

Noted.
3. What's the biggest number of elements that your array can have?
Check your platform docs. It may be more than int can handle, but less than or equal to what size_t can handle.

The platform limit is 64KB for any one item (i8086). The array would
be the limiting factor in this case (at something over 5,000 elements),
but it's never going to get that big - the maximum dimension is 512.

If size_t isn't actually an int (of some standard type), isn't that
going to be a problem in the for()? I thought the index variable had
to be an integer or enumeration.
4. Always put a return statement in main. It's necessary in C89, and good style in C99.

....

Thanks.

Nov 14 '05 #19
gtippery wrote:
<snip>
3. What's the biggest number of elements that your array can have?
Check your platform docs. It may be more than int can handle, but less
than or equal to what size_t can handle.


The platform limit is 64KB for any one item (i8086). The array would
be the limiting factor in this case (at something over 5,000

elements),

[OT]

The limits change depending on the compiler / memory model combination.
I know there's one out there (a huge model variant) using 16 bit int
and 32 bit size_t. Can't remember which compiler, and don't care to--
hopefully my DOS programming days are far behind me (pun intended),
never to return.

<snip>
If size_t isn't actually an int (of some standard type), isn't that
going to be a problem in the for()? I thought the index variable had
to be an integer or enumeration.


The standard states (7.17) that "size_t [...] is the unsigned integer
type of the result of the sizeof operator". Use it like any other
integral type, including in for statements and subscripting operators
(ie []). Generally, size_t is a better choice than int for array
subscripting.

So, making a few simple modifications to my previously posted code:

---snip---
#include <stdio.h>

#define MAXCOL 2
#define NAMLEN 8
#define EXTLEN 3

struct NameExt
{
char name[NAMLEN];
char ext[EXTLEN];
};
int main(void)
{
/* Some sample filenames */
struct NameExt list[] = {
{ "One ", "1 " },
{ "TwoTwo ", "22 " },
{ "ThreeThr", "333" },
{ "Four ", "4 " },
{ "FiveFive", "55 " },
{ "SixSixSi", "666" },
};

/* Print the array out */
size_t i;
for(i = 0; i < sizeof(list) / sizeof(list[0]); i++)
printf("%-*.*s.%-*.*s%s",
NAMLEN, NAMLEN, list[i].name,
EXTLEN, EXTLEN, list[i].ext,
(i + 1) % MAXCOL ? " " : "\n");

return 0;
}
--- snip ---

[mark@icepick ~]$ gcc -Wall -O2 -ansi -pedantic foo.c -o foo
[mark@icepick ~]$ ./foo
One .1 TwoTwo .22
ThreeThr.333 Four .4
FiveFive.55 SixSixSi.666

I believe that's what you're looking for. That's the simplest code I
can think of off the top of my head.
Mark F. Haigh
mf*****@sbcglobal.net

Nov 14 '05 #20
Mark F. Haigh wrote:
gtippery wrote:
<snip>

If size_t isn't actually an int (of some standard type), isn't that
going to be a problem in the for()? I thought the index variable had to be an integer or enumeration.

The standard states (7.17) that "size_t [...] is the unsigned integer
type of the result of the sizeof operator". Use it like any other
integral type, including in for statements and subscripting operators
(ie []). Generally, size_t is a better choice than int for array
subscripting.


I still don't understand why it's "better", by which I suppose you mean
"bigger" (meaning wider range - for positive values, of course).
Wouldn't an implementation with e.g. 16-bit size_t and 32-bit type int
meet the spec you quote? Do you mean it's _likely_ to be bigger? Or
do you just mean that for a given size, unsigned int is (probably)
"bigger" than signed int?

Or maybe I've missed the point. Other than range, is there some reason
specific to array subscripting to prefer size_t ?

So, making a few simple modifications to my previously posted code:

---snip---
#include <stdio.h>

#define MAXCOL 2
#define NAMLEN 8
#define EXTLEN 3

struct NameExt
{
char name[NAMLEN];
char ext[EXTLEN];
};
int main(void)
{
/* Some sample filenames */
struct NameExt list[] = {
{ "One ", "1 " },
{ "TwoTwo ", "22 " },
{ "ThreeThr", "333" },
{ "Four ", "4 " },
{ "FiveFive", "55 " },
{ "SixSixSi", "666" },
};

/* Print the array out */
size_t i;
for(i = 0; i < sizeof(list) / sizeof(list[0]); i++)
printf("%-*.*s.%-*.*s%s",
NAMLEN, NAMLEN, list[i].name,
EXTLEN, EXTLEN, list[i].ext,
(i + 1) % MAXCOL ? " " : "\n");

return 0;
}
--- snip ---

[mark@icepick ~]$ gcc -Wall -O2 -ansi -pedantic foo.c -o foo
[mark@icepick ~]$ ./foo
One .1 TwoTwo .22
ThreeThr.333 Four .4
FiveFive.55 SixSixSi.666

I believe that's what you're looking for. That's the simplest code I
can think of off the top of my head.
Mark F. Haigh
mf*****@sbcglobal.net


That is indeed the desired output format, and indeed simple. With
luck, the compiler will factor out the constant expression in the for's
test expression.

I note you've changed the internal data representation somewhat, but I
assume it was just to simplify the example by using preinitialization.
I wanted to do that for the initial posting, but couldn't figure out
how. Is that an array of structures of strings? (As I mentioned, I
have trouble with C's declaration syntax, but I'm learning -- I hope.)

Nov 14 '05 #21
gtippery wrote:
Mark F. Haigh wrote:
gtippery wrote:
<snip>
If size_t isn't actually an int (of some standard type), isn't that
going to be a problem in the for()? I thought the index variable
had
to be an integer or enumeration.


The standard states (7.17) that "size_t [...] is the unsigned integer
type of the result of the sizeof operator". Use it like any other
integral type, including in for statements and subscripting operators
(ie []). Generally, size_t is a better choice than int for array
subscripting.


I still don't understand why it's "better", by which I suppose you mean
"bigger" (meaning wider range - for positive values, of course).
Wouldn't an implementation with e.g. 16-bit size_t and 32-bit type int
meet the spec you quote? Do you mean it's _likely_ to be bigger? Or
do you just mean that for a given size, unsigned int is (probably)
"bigger" than signed int?

Or maybe I've missed the point. Other than range, is there some reason
specific to array subscripting to prefer size_t ?


size_t is the type of the result of the sizeof operator and the
type of argument taken by the dynamic memory allocation routines
malloc/calloc/realloc -- so, basically, every object you work with
has a size in bytes which can be expressed in size_t. The same
guarantee does not hold for short, int, long of either signed or
unsigned variety. So, using size_t for your index variables, you
can _never_ (*) go wrong. The downside is that you have to be
more careful with your loop tests as unsigned integer types never
can provide values <0.

(*) never: There are no absolutes. Using automatic or static
or dynamically allocated storage, within standard C you will be
on the safe side. Note that size_t has not to be large enough
to count, for example, the number of bytes in a file.

[snip: solved problem]
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #22
gtippery wrote:
<large snip>

I still don't understand why it's "better", by which I suppose you mean "bigger" (meaning wider range - for positive values, of course).
Wouldn't an implementation with e.g. 16-bit size_t and 32-bit type int meet the spec you quote? Do you mean it's _likely_ to be bigger? Or
do you just mean that for a given size, unsigned int is (probably)
"bigger" than signed int?

Or maybe I've missed the point. Other than range, is there some reason specific to array subscripting to prefer size_t ?
When you're talking about the *size* of things, use size_t. Take the
canonical example (incidentially, on a DOS-like platform):

#define SIZE 20000
char buf[SIZE];

Let's say it was changed to:

#define SIZE 40000

The thing is, any loop using a signed int (16 bit) index will fail
after element 32767, causing undefined behavior (signed integer
overflow). A size_t would make it to the maximum *size* buf can be.
The size of int is really unrelated to the maximum size of objects.

<large snip>
That is indeed the desired output format, and indeed simple. With
luck, the compiler will factor out the constant expression in the for's test expression.

I note you've changed the internal data representation somewhat, but I assume it was just to simplify the example by using preinitialization. I wanted to do that for the initial posting, but couldn't figure out
how. Is that an array of structures of strings? (As I mentioned, I
have trouble with C's declaration syntax, but I'm learning -- I

hope.)

The internal data representation is the same as you need. C does not
include the terminating null ('\0') if there is no room for it:

6.7.8 Initialization

[...]

[#14] An array of character type may be initialized by a
character string literal, optionally enclosed in braces.
Successive characters of the character string literal
(including the terminating null character if there is room
or if the array is of unknown size) initialize the elements
of the array.

Since the size of each array is specified in each case (8 and 3,
respectively), if you provide exactly 8 and exactly 3 characters for
each initializer, the \0 will not be tacked on to the end. In other
words, the C implementation will not overflow the buffer for you, it'll
leave you to do that on your own. ;-)

Keep it up. We like the hard questions around here.
Mark F. Haigh
mf*****@sbcglobal.net

Nov 14 '05 #23
Michael Mair wrote:
size_t is the type of the result of the sizeof operator and the
type of argument taken by the dynamic memory allocation routines
malloc/calloc/realloc -- so, basically, every object you work with
has a size in bytes which can be expressed in size_t. The same
guarantee does not hold for short, int, long of either signed or
unsigned variety.


The same guarantee has to hold for the highest ranking
unsigned type, which is unsigned long in C89.
size_t has the option of being smaller than the highest ranking
unsigned type, for implementations where that may be desirable.
Nov 14 '05 #24

Michael Mair wrote:
....
Note that size_t has not to be large enough
to count, for example, the number of bytes in a file.


"has not to be"? Ah, was that idiom for "does not have to be", or typo
for "has got to be"?

Nov 14 '05 #25
pete wrote:
Michael Mair wrote:
size_t is the type of the result of the sizeof operator and the
type of argument taken by the dynamic memory allocation routines
malloc/calloc/realloc -- so, basically, every object you work with
has a size in bytes which can be expressed in size_t. The same
guarantee does not hold for short, int, long of either signed or
unsigned variety.


The same guarantee has to hold for the highest ranking
unsigned type, which is unsigned long in C89.
size_t has the option of being smaller than the highest ranking
unsigned type, for implementations where that may be desirable.


I'm thinking perhaps a segmented or paged architecture. Wider
operands, but paged addressing using fewer address bits. Seems to me a
number of older computers were like this, as well as some present-day
microcontrollers (i8051?)

And some nominally 32-bit machines have a wider integer type supported
by their FPU. You can calculate with it, but you can't address with
it.

Nov 14 '05 #26

Mark F. Haigh wrote:

....
The internal data representation is the same as you need. C does not
include the terminating null ('\0') if there is no room for it:

6.7.8 Initialization

[...]

[#14] An array of character type may be initialized by a
character string literal, optionally enclosed in braces.
Successive characters of the character string literal
(including the terminating null character if there is room
or if the array is of unknown size) initialize the elements
of the array.

Since the size of each array is specified in each case (8 and 3,
respectively), if you provide exactly 8 and exactly 3 characters for
each initializer, the \0 will not be tacked on to the end. In other
words, the C implementation will not overflow the buffer for you, it'll leave you to do that on your own. ;-)

That's handy. What happens if you initialize a char[8] with
"123456789"? I mean, I can check what "happens" for me, but what's
_supposed_ to happen?
Keep it up. We like the hard questions around here.


That's _definitely_ a Good Thing <grin>.

Nov 14 '05 #27
gtippery wrote:
Michael Mair wrote:
...
Note that size_t has not to be large enough
to count, for example, the number of bytes in a file.


"has not to be"? Ah, was that idiom for "does not have to be", or typo
for "has got to be"?


The former ;-)

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #28
pete wrote:
Michael Mair wrote:

size_t is the type of the result of the sizeof operator and the
type of argument taken by the dynamic memory allocation routines
malloc/calloc/realloc -- so, basically, every object you work with
has a size in bytes which can be expressed in size_t. The same
guarantee does not hold for short, int, long of either signed or
unsigned variety.


The same guarantee has to hold for the highest ranking
unsigned type, which is unsigned long in C89.
size_t has the option of being smaller than the highest ranking
unsigned type, for implementations where that may be desirable.


Thanks for the expansion -- I thought I'd better leave that
out as we then get to C89 vs. C99.
size_t does always fit.

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #29
gtippery wrote:
That's handy. What happens if you initialize a char[8] with
"123456789"? I mean, I can check what "happens" for me, but what's
_supposed_ to happen?


char array[8] = "123456789";
is undefined.
It violates a "shall constraint".

N869
6.7.8 Initialization
[#2] No initializer shall attempt to provide a value for an
object not contained within the entity being initialized.

--
pete
Nov 14 '05 #30

pete wrote:
gtippery wrote:
That's handy. What happens if you initialize a char[8] with
"123456789"? I mean, I can check what "happens" for me, but what's
_supposed_ to happen?


char array[8] = "123456789";
is undefined.
It violates a "shall constraint".

N869
6.7.8 Initialization
[#2] No initializer shall attempt to provide a value for an
object not contained within the entity being initialized.

--
pete


That interpretation isn't very obvious to me from what you quote;
perhaps it is in the larger context. (Can't check, the copy I
downloaded only goes to 4.13, including the library. Either it got
renumbered or we're on different versions.)
Sounds to me like it's saying you can't initialize object z in object
y's initializer unless z is part of y.

Nov 14 '05 #31
In article <11**********************@g14g2000cwa.googlegroups .com>,
gtippery <gt******@altavista.net> wrote:

:pete wrote:
:> char array[8] = "123456789";
:> is undefined.
:> It violates a "shall constraint".

:That interpretation isn't very obvious to me from what you quote;

The initializer is attempting to provide a value for the
"object" which is the character at array+8, but that object is
not part of the object array[] which is being initialized, since
array[] goes from array+0 to array+7.
--
History is a pile of debris -- Laurie Anderson
Nov 14 '05 #32
"gtippery" <gt******@altavista.net> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...

pete wrote:
gtippery wrote:
That's handy. What happens if you initialize a char[8] with
"123456789"? I mean, I can check what "happens" for me, but what's
_supposed_ to happen?


char array[8] = "123456789";
is undefined.
It violates a "shall constraint".

N869
6.7.8 Initialization
[#2] No initializer shall attempt to provide a value for an
object not contained within the entity being initialized.

--
pete


That interpretation isn't very obvious to me from what you quote;
perhaps it is in the larger context. (Can't check, the copy I
downloaded only goes to 4.13, including the library. Either it got
renumbered or we're on different versions.)
Sounds to me like it's saying you can't initialize object z in object
y's initializer unless z is part of y.


Your initializer is trying to provide values for array[8] and array[9],
which are not containted within the char[8] object called "array". The
behavior is undefined.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Nov 14 '05 #33
gtippery wrote:

pete wrote:
char array[8] = "123456789";
is undefined.
It violates a "shall constraint".

N869
6.7.8 Initialization
[#2] No initializer shall attempt to provide a value for an
object not contained within the entity being initialized.

That interpretation isn't very obvious to me from what you quote;
perhaps it is in the larger context. (Can't check, the copy I
downloaded only goes to 4.13, including the library. Either it got
renumbered or we're on different versions.)
Sounds to me like it's saying you can't initialize object z in object
y's initializer unless z is part of y.


That's what I'm saying.
I think the language is a little plainer in the C89 standard.

http://dev.unicals.com/papers/c89-draft.html#3.5.7

3.5.7 Initialization
Constraints

There shall be no more initializers in an initializer list
than there are objects to be initialized.

--
pete
Nov 14 '05 #34
pete <pf*****@mindspring.com> wrote:

I think the language is a little plainer in the C89 standard.

http://dev.unicals.com/papers/c89-draft.html#3.5.7

3.5.7 Initialization
Constraints

There shall be no more initializers in an initializer list
than there are objects to be initialized.


That language had to change in C99 due to designated initializers. For
example:

int a[10] = {[11] = 0};

is invalid even though there are 10 objects and only one initializer.

-Larry Jones

Years from now when I'm successful and happy, ...and he's in
prison... I hope I'm not too mature to gloat. -- Calvin
Nov 14 '05 #35
la************@ugs.com wrote:
pete <pf*****@mindspring.com> wrote:
I think the language is a little plainer in the C89 standard.

http://dev.unicals.com/papers/c89-draft.html#3.5.7

3.5.7 Initialization
Constraints

There shall be no more initializers in an initializer list
than there are objects to be initialized.

That language had to change in C99 due to designated initializers. For
example:

int a[10] = {[11] = 0};

is invalid even though there are 10 objects and only one initializer.

-Larry Jones

Years from now when I'm successful and happy, ...and he's in
prison... I hope I'm not too mature to gloat. -- Calvin


Given..
int a[10] = {[11] = 0};
^^^^^^^^^^
...I have never seen an initializer like that. What do you think it
means? What is the type of this expression?
--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #36
In article <Tp********************@comcast.com>,
Joe Wright <jo********@comcast.net> wrote:
Given..
int a[10] = {[11] = 0};
^^^^^^^^^^
..I have never seen an initializer like that.
It's a C99ism.
What do you think it
means? What is the type of this expression?


It means precisely what 6.7.8#6 of n869 (and, unless the numbering has
changed, the same paragraph of C99) says it means, and has the type that
the same paragraph says it has.

(In this case, it's an attempt to initialize an array[10] of int with
an initializer of type array[more-than-10], which is what makes it an
appropriate example of an invalid initializer.)
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
You know, you should never say something like "No one is expecting..." on
Usenet. It is just too easy to disprove. The preferred form is "No one in his
right mind is expecting..." --Stephan H.M.J. Houben in comp.lang.scheme
Nov 14 '05 #37
Joe Wright <jo********@comcast.net> wrote:

Given..
int a[10] = {[11] = 0};
^^^^^^^^^^
..I have never seen an initializer like that. What do you think it
means? What is the type of this expression?


It's a designated initializer (a new feature in C99) -- it's an attempt
to initialize a[11] to 0 (which is invalid since a only has 10
elements). Since it's not an expression, it has no type. A more
complete (and valid!) example:

int a[10] = {0, 1, [7] = 7, 8, [2] = 2, 3, 4};

explicitly initalizes a[0] to 0, a[1] to 1, a[2] to 2, a[3] to 3, a[4]
to 4, a[7] to 7, a[8] to 8, and implicitly initializes all the other
elements to 0. There's a similar construct for struct and union
members and they can be combined:

struct foo s = {.x = 10, .y = 20, .u.z = 4, .a[3] = 3};

-Larry Jones

What's Santa's definition? How good do you have to be to qualify as good?
-- Calvin
Nov 14 '05 #38

pete wrote:
That's what I'm saying.
I think the language is a little plainer in the C89 standard.

http://dev.unicals.com/papers/c89-draft.html#3.5.7

3.5.7 Initialization
Constraints

There shall be no more initializers in an initializer list
than there are objects to be initialized.

--
pete


Yeah, that'd cover it. I forget an array isn't "an object".

Nov 14 '05 #39
gtippery wrote:

pete wrote:
That's what I'm saying.
I think the language is a little plainer in the C89 standard.

http://dev.unicals.com/papers/c89-draft.html#3.5.7

3.5.7 Initialization
Constraints

There shall be no more initializers in an initializer list
than there are objects to be initialized
Yeah, that'd cover it. I forget an array isn't "an object".


Array types are aggregate types.
Members of aggregate type objects are also objects.

--
pete
Nov 14 '05 #40

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Andreas Falck | last post by:
Hi, I ran the code below on two different versions, 4.0.14 and 4.0.16 respectively, both running RH 7.3 on intel. In version mysql server version 4.0.14 the SELECT privelege suffices for...
0
by: Daniel | last post by:
Hi there, I recently came across an interesting option when right clicking on a project (Right click on the project -> properties -> Configuration Properties ->Build -> Optimize) There is an...
6
by: Silly | last post by:
byte Name = new byte; uint len = (uint)Name.Length; uint err = MyFunction(devID, out Name, out len); When this code is run in release build with optimize code set to true, len is evaluated to...
15
by: kenneth | last post by:
I was trying to use multiple thread to optimize my following code, but met some problems, anyone can help me? k are initialized. int computePot() { int i, j; for( i=0; i<500; i++ ) { for(...
4
by: George2 | last post by:
Hello everyone, Why Visual Studio compiler can not optimize in this case? I think this case is almost the same as sample 1, why compiler can optimize sample 1 but can not optimze sample 2? ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.