Hi all,
In the Gnulib documentation, section "C99 features assumed by Gnulib",
we list:
* A declaration after a statement, or as the first clause in a for statement.
The last compiler that did not support this was IRIX cc, which we don't
support for many years now.
But, so far, we have not made much use of the opportunity of adopting
this C99 style.
I plan to refactor the source code (excluding the one shared with glibc) to
- mix declarations and statements, so that variable declarations and
initializations get closer together,
- reduce the scope of local variables,
- use the common style of declaring a 'for' iteration variable
directly in the 'for' clause.
The reason is that
- When reading code, the declarations of variables 20 or 50 lines
before their first use just feels inappropriate.
- It follows the more general principle
"Keep related things close together".
- See also this thread [1].
In other words, a function definition that starts like this:
------------------------------------------------------------------------
FTSENT *
fts_read (register FTS *sp)
{
register FTSENT *p, *tmp;
register unsigned short int instr;
register char *t;
------------------------------------------------------------------------
is just a hindrance to understanding the code.
For instance, I will convert
------------------------------------------------------------------------
const char **
prepare_spawn (const char * const *argv, char **mem_to_free)
{
size_t argc;
const char **new_argv;
size_t i;
/* Count number of arguments. */
for (argc = 0; argv[argc] != NULL; argc++)
;
/* Allocate new argument vector. */
new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
if (new_argv == NULL)
return NULL;
/* Add an element upfront that can be used when argv[0] turns out to be a
script, not a program.
On Unix, this would be "/bin/sh". */
new_argv[0] = "sh.exe";
/* Put quoted arguments into the new argument vector. */
size_t needed_size = 0;
for (i = 0; i < argc; i++)
{
const char *string = argv[i];
const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
size_t length = strlen (quoted_string);
needed_size += length + 1;
}
char *mem;
if (needed_size == 0)
mem = NULL;
else
{
mem = (char *) malloc (needed_size);
if (mem == NULL)
{
/* Memory allocation failure. */
free (new_argv);
errno = ENOMEM;
return NULL;
}
}
*mem_to_free = mem;
for (i = 0; i < argc; i++)
{
const char *string = argv[i];
new_argv[1 + i] = mem;
const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
size_t length = strlen (quoted_string);
memcpy (mem, quoted_string, length + 1);
mem += length + 1;
}
new_argv[1 + argc] = NULL;
return new_argv;
}
------------------------------------------------------------------------
to
------------------------------------------------------------------------
const char **
prepare_spawn (const char * const *argv, char **mem_to_free)
{
/* Count number of arguments. */
size_t argc;
for (argc = 0; argv[argc] != NULL; argc++)
;
/* Allocate new argument vector. */
const char **new_argv =
(const char **) malloc ((1 + argc + 1) * sizeof (const char *));
if (new_argv == NULL)
return NULL;
/* Add an element upfront that can be used when argv[0] turns out to be a
script, not a program.
On Unix, this would be "/bin/sh". */
new_argv[0] = "sh.exe";
/* Put quoted arguments into the new argument vector. */
size_t needed_size = 0;
for (size_t i = 0; i < argc; i++)
{
const char *string = argv[i];
const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
size_t length = strlen (quoted_string);
needed_size += length + 1;
}
char *mem;
if (needed_size == 0)
mem = NULL;
else
{
mem = (char *) malloc (needed_size);
if (mem == NULL)
{
/* Memory allocation failure. */
free (new_argv);
errno = ENOMEM;
return NULL;
}
}
*mem_to_free = mem;
for (size_t i = 0; i < argc; i++)
{
const char *string = argv[i];
new_argv[1 + i] = mem;
const char *quoted_string = (string[0] == '\0' ? "\"\"" : string);
size_t length = strlen (quoted_string);
memcpy (mem, quoted_string, length + 1);
mem += length + 1;
}
new_argv[1 + argc] = NULL;
return new_argv;
}
------------------------------------------------------------------------
I wouldn't have liked this style in 2000. But by now, everyone should
be familiar with this style (and the "declare all local variables up-front"
style has become less and less used over time).
Bruno
[1]
https://www.reddit.com/r/C_Programming/comments/dbaeno/where_is_the_best_place_to_declare_variables/?utm_source=chatgpt.com