Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Some potential Defect Reports

12 views
Skip to first unread message

Clive D. W. Feather

unread,
Jun 12, 2001, 11:00:08 AM6/12/01
to
As I've said before, I look for potential DR topics in this group. I
have assembled a batch of 16 for WG14. These have *not* yet been
formally submitted, since this has to be done by the UK National Body.


====
Potential Defect Report 1

Subject: constant expressions and unevaluated subexpressions
-------

Problem
-------

Consider the code:

#define ALPHA 0
#define BRAVO 0
#if ALPHA ? (1,1) : BRAVO ? (x=1) : 1

6.6 says:

[#3] Constant expressions shall not contain assignment,
increment, decrement, function-call, or comma operators,
except when they are contained within a subexpression that
is not evaluated.95

Naively one would therefore expect the #if line to be forbidden.
However, if both ALPHA and BRAVO are defined as 0, neither the comma
operator nor the assignment operator is evaluated, so this does not
forbid them. 6.10.1 does not contain any wording that would affect this.
This appears undesirable to me.

The distinction is between expressions that are not evaluated for syntax
reasons (e.g. "&*x" or "sizeof (x = 1)") and those are not evaluated for
evaluation reasons (e.g. "x && y" or "x ? y : z"). The former are fine,
but the latter should be forbidden.


Suggested Technical Corrigendum
-------------------------------

Change 6.6#3 to:

[#3] Constant expressions shall not contain assignment,
increment, decrement, function-call, or comma operators,
except when they are contained within a subexpression that
is not evaluated; for this purpose all the operands of the &&
|| and ?: operators are deemed to be evaluated.95

and change footnote 95 to:

95)The operand of a sizeof operator is usually not evaluated
(6.5.3.4). Thus "sizeof(x=1)" is a constant expression if
x has been declared appropriately, but "0 && (x=1)" is not.


====
Potential Defect Report 2

Subject: completion of declarators
-------

Problem
-------

6.2.1#7 reads in part:

Any other identifier has scope that begins just after the
completion of its declarator.

However, nothing says when a declarator is completed. While it seems
obvious to experienced people that this means the syntactic end of the
declarator, the term "complete" has other meanings when discussing
declarations and objects, and therefore it's a bad term to use.


Suggested Technical Corrigendum
-------------------------------

Change the quoted text to:

Any other identifier has scope that begins just after the
end of the declarator it appears in.


====
Potential Defect Report 3

Subject: lacunae in exact-width integer types
-------

Problem
-------

7.18.1.1 reads:

[#1] The typedef name intN_t designates a signed integer
type with width N, no padding bits, and a two's complement
representation. Thus, int8_t denotes a signed integer type
with a width of exactly 8 bits.

[#2] The typedef name uintN_t designates an unsigned integer
type with width N. Thus, uint24_t denotes an unsigned
integer type with a width of exactly 24 bits.

[#3] These types are optional. However, if an
implementation provides integer types with widths of 8, 16,
32, or 64 bits, it shall define the corresponding typedef
names.

The requirements for no padding bits and two's complement were added at
a late stage, and the implications to the text weren't fully thought
through. In particular:
- the second sentence of #1 is inconsistent with the first;
- the unsigned types also need the "no padding bits" requirement;
- the requirements in #3 aren't the same as those in #1, so an
implementation can't have 8 bit types *with* padding bits.


Suggested Technical Corrigendum
-------------------------------

Change this section to read:

[#1] The typedef name intN_t designates a signed integer
type with width N, no padding bits, and a two's complement
representation. Thus, int8_t denotes a signed integer type
with a width of exactly 8 bits and those other properties.

[#2] The typedef name uintN_t designates an unsigned integer
type with width N and no padding bits. Thus, uint24_t denotes an
unsigned integer type with a width of exactly 24 bits and no
padding bits.

[#3] These types are optional. However, if an
implementation provides integer types with widths of 8, 16,
32, or 64 bits, no padding bits, and (for the signed types)
have a two's complement representation, it shall define the
corresponding typedef names.

Or, alternatively:

[#3] These types are optional. However, if an
implementation has a type with width 8, 16, 32, or 64 bits that
meet the above requirements, it shall define the corresponding
typedef names.


====
Potential Defect Report 4

Subject: are values a form of behaviour ?
-------

Problem
-------

I can see nothing that says or implies that production of an unspecified
value is a form of unspecified behaviour, and similarly for
implementation-defined values. It is therefore arguable that a program
is strictly-conforming even if its output depends on an unspecified
value.


Suggested Technical Corrigendum
-------------------------------

Add a new paragraph 4#2a after 4#2:

[#2a] An evaluation that makes use of an unspecified or
implementation-defined value is a form of unspecified or
implementation-defined behaviour respectively.


====
Potential Defect Report 5

Subject: limits are required for optional types
-------

Problem
-------

The types sig_atomic_t and wchar_t are optional on freestanding
implementations, since they don't have to provide the relevant headers.
But the limits SIG_ATOMIC_MIN, SIG_ATOMIC_MAX, WINT_MIN, and WINT_MAX
are in <stdint.h>, which all implementations must provide. So a
freestanding implementation must provide limits for types which it
doesn't implement.


Suggested Technical Corrigendum
-------------------------------

Append to 7.18.3#2:

A freestanding implementation shall only define the symbols
corresponding to the types it actually provides.


====
Potential Defect Report 6

Subject: wint_t is not the promoted version of wchar_t
-------

Problem
-------

In the fprintf conversion specifier "%lc", the corresponding argument is
of type wint_t, but is then treated as if it contained a wchar_t value.
In 7.19.6.1#18, the last call is:

fprintf(stdout, "|%13lc|\n", wstr[5]);

This argument has the type wchar_t.

There is no requirement in the Standard that the default argument
promotions convert wchar_t to wint_t. Therefore this example exhibits
undefined behaviour on some implementations. Nonetheless, the code looks
like it ought to work, and WG14 should consider changing the definition
of wint_t to force it.

The current definition of wint_t is in 7.24.1#2:

wint_t

which is an integer type unchanged by default argument
promotions that can hold any value corresponding to members
of the extended character set, as well as at least one value
that does not correspond to any member of the extended
character set (see WEOF below);269) and

269wchar_t and wint_t can be the same integer type.

Three possible solutions are:
(1) Fix the example.
(2) Change the definition of wint_t to be the promoted version of
wchar_t.
(3) Change the definition of %lc to take promoted wchar_t rather than
wint_t.


Suggested Technical Corrigendum 1
---------------------------------

Change the quoted line of 7.19.6.1#18 to:

fprintf(stdout, "|%13lc|\n", (wint_t) wstr[5]);


Suggested Technical Corrigendum 2
---------------------------------

Change the cited portion of 7.24.1#2 to:

wint_t

which is the integer type resulting when the default argument
promotions are applied to the type wchar_t;269) and


Suggested Technical Corrigendum 3
---------------------------------

Change 7.19.6.1#7 and 7.24.2.1#7, l modifier, to:

l (ell) Specifies that a following d, i, o, u, x, or X
conversion specifier applies to a long int or
unsigned long int argument; that a following n
conversion specifier applies to a pointer to a
long int argument; that a following c
conversion specifier applies to an argument ||
whose type is that resulting when the default ||
argument conversions are applied to the type ||
wchar_t; that a following s conversion ||
specifier applies to a pointer to a wchar_t
argument; or has no effect on a following a, A,
e, E, f, F, g, or G conversion specifier.

Change 7.19.6.1#8, c specifier, second paragraph, to:

If an l length modifier is present, the argument ||
- whose type is that resulting when the default ||
argument conversions are applied to the type wchar_t - ||
is converted as if by an ls conversion
specification with no precision and an argument that
points to the initial element of a two-element array
of wchar_t, the first element containing the ||
argument to the lc conversion specification and the
second a null wide character.

Change 7.24.2.1#8, c specifier, second paragraph, to:

If an l length modifier is present, the ||
argument is converted to wchar_t and written.


====
Potential Defect Report 7

Subject: Lacuna applying C89:TC1 to C99
-------

Problem
-------

Defect Report 009 made a change to the text concerning function
declarators. This text seems not have made it into C99, even though the
issue remains valid. The change should be reinstated.


Suggested Technical Corrigendum
-------------------------------

Change 6.7.5.3#11 to:

[#11] If, in a parameter declaration, an identifier can be
treated as a typedef name or as a parameter name, it shall be
taken as a typedef name.


====
Potential Defect Report 8

Subject: non-directives within macro arguments
-------

Problem
-------

Consider the code:

#define nothing(x) // Nothing

/* Case 1 */
nothing (
#include <stdio.h>
)

/* Case 2 */
nothing (
#nonstandard
)

6.10.3#11 reads in part:

If
there are sequences of preprocessing tokens within the list
of arguments that would otherwise act as preprocessing
directives, the behavior is undefined.

This clearly covers case 1. However, it is not clear whether or not case
2 is a preprocessing directive. It is a "non-directive", but is that
also a directive ? If case 2 is a directive, it is undefined behaviour.
If it is not, then case 2 is strictly-conforming and macro-expands to
nothing.

Since non-directives are only valid as extensions, it might be more
sensible for them to behave as directives do and make the behaviour
undefined in this case.


Suggested Technical Corrigendum
-------------------------------

In 6.10.3#11, change the last-sentence to:

If
there are sequences of preprocessing tokens within the list
of arguments that would otherwise act as preprocessing
directives or as non-directives (that is, the first pre-processing
token on a line is a #), the behavior is undefined.


====
Potential Defect Report 9

Subject: are "struct fred" and "union fred" the same type ?
-------

Problem
-------

Consider the code:

union fred { int a; }

int main (void)
{
struct fred *ptr; /* Line X */
// ...

I can see nothing that forbids this code. In particular, 6.7.2.3#8
reads:

[#8] If a type specifier of the form

struct-or-union identifier
or
enum identifier

occurs other than as part of one of the above forms, and a
declaration of the identifier as a tag is visible, then it
specifies the same type as that other declaration, and does
not redeclare the tag.

At line X a declaration of "fred" as a tag is visible, so this line
specifies the same type as that other declaration, even though this uses
"struct" and that uses "union" !


Suggested Technical Corrigendum
-------------------------------

Add a new paragraph following 6.7.2.3#1:

[#1a] Where two declarations that use the same tag declare the
same type, they shall both use the same choice of struct, union,
or enum.


====
Potential Defect Report 10

Subject: incomplete argument types when calling non-prototyped functions
-------

Problem
-------

Consider the code:

void jim ();
void sheila (void);

// ...

sheila (jim ()); /* Line A */
jim (sheila ()); /* Line B */

Line A violates the constraint of 6.5.2.2#2, that requires the argument
to have a type that can be assigned to the parameter type. But line B
doesn't because that constraint only applies to prototyped functions.
6.5.2.2#4 reads in part:

[#4] An argument may be an expression of any object type.

but this is not a constraint. Should it not be ? After all, the compiler
has to know the type of the argument in order to compile the function
call, so it can check at that point that the argument has a complete
object type.


Suggested Technical Corrigendum
-------------------------------

Add a new paragraph #1a following 6.5.2.2#1:

[#1a] Each argument shall have a type which is a completed object
type.


====
Potential Defect Report 11

Subject: "overriding" in designated initializers
-------

Problem
-------

Consider the code:

struct fred
{
char s [6];
int n;
};
struct fred x [] = { { { "abc" }, 1 }, [0].s[0] = 'q' };
struct fred y [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };

Both x and y will contain one element of type struct fred, which will be
initialized by the initializer "{ { "abc" }, 1 }" and then modified in
some way. The question is exactly how it is modified.

6.7.8#19 reads:

[#19] The initialization shall occur in initializer list
order, each initializer provided for a particular subobject
overriding any previously listed initializer for the same
subobject; all subobjects that are not initialized
explicitly shall be initialized implicitly the same as
objects that have static storage duration.

In the case of x, it is fairly clear that the first initializer sets:
x [0].s [0] = 'a'
x [0].s [1] = 'b'
x [0].s [2] = 'c'
x [0].s [3] = '\0'
x [0].n = 1
and the second one sets:
x [0].s [0] = 'q'
Finally, the remaining subobjects are initialized implicitly:
x [0].s [4] = 0
x [0].s [5] = 0

Now consider the second initializer for y. One point of view says that
this behaves the same as for x: it specifies a value for y [0].s [0],
after which the two remaining elements of y [0].s are still
uninitialized and so are set to zero. The other point of view says that
this sets:
y [0] = (struct fred) { .s[0] = 'q' }
and that the rule concerning "all subobjects that are not initialized
explicitly" applies recursively. If so, the effect is to set:

x [0].s [0] = 'q'
x [0].s [1] = 0
x [0].s [2] = 0
x [0].s [3] = 0
x [0].s [4] = 0
x [0].s [5] = 0
x [0].n = 0

Which of these is correct ?


Suggested Technical Corrigendum 1
---------------------------------

If x and y are supposed to have the same effect, change 6.7.8#19 to:

[#19] The initialization shall occur in initializer list
order, each initializer provided for a particular subobject
overriding any previously listed initializer for the same
subobject. When all initializers have been applied, any subobjects
of the overall object being initialized that have not been
initialized explicitly shall be initialized implicitly the
same as objects that have static storage duration.

and add a new paragraph at the end:

[#39] To illustrate the rules for implicit initialization, in:

struct fred
{
char s [6];
int n;
};
struct fred x [] = { { { "abc" }, 1 }, [0].s[0] = 'q' };
struct fred y [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };

the definitions of x and y result in identical objects. Each will be
an array with one element; within that element, the members s[4] and
s[5] are implicitly initialized to zero.


Suggested Technical Corrigendum 2
---------------------------------

If x and y are supposed to be different, change 6.7.8#19 to:

[#19] The initialization shall occur in initializer list
order, each initializer provided for a particular subobject
overriding any previously listed initializer for the same
subobject; for each brace-enclosed list, all subobjects within
the object that that list initializes that are not initialized
explicitly shall be initialized implicitly the same as
objects that have static storage duration.

and add a new paragraph at the end:

[#39] To illustrate the rules for implicit initialization, in:

struct fred
{
char s [6];
int n;
};
struct fred x [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };
struct fred y [] = { { .s[0] = 'q' } };

the definitions of x and y result in identical objects. Each will be
an array with one element; within that element, all the members are
implicitly initialized to zero except for s[0]. In the definition of
x the first initializer has no effect, since the second one
initializes the same subobject (x[0]).


====
Potential Defect Report 12

Subject: all-zero bits representations
-------

Problem
-------

Consider the code:

int v [10];
memset (v, 0, sizeof v);

Most programmers would expect this code to set all the elements of v to
zero. However, the code is actually undefined: it is possible for int to
have a representation in which all-bits-zero is a trap representation
(for example, if there is an odd-parity bit in the value).

This problem applies to all integer types except for unsigned char. I
believe that the idiom is well-enough known that it should be made a
part of the Standard.


Suggested Technical Corrigendum
-------------------------------

Append to 6.2.6.2#5:

For any integer type, the object representation where all the
bits are zero shall be a representation of the value zero in
that type.


====
Potential Defect Report 13

Subject: lacuna in iswctype and towctrans
-------

Problem
-------

Consider the calls:

iswctrans (c, wctype (property))
towctrans (c, wctrans (property))

where property is not valid in the current locale. The wctype and
wctrans functions return zero, but the behaviour of iswctype and
towctrans is not specified.

I believe it would be useful - and considered natural - for them to
return 0 ("c does not have this property") and c ("c is unaffected by
this mapping") respectively.


Suggested Technical Corrigendum
-------------------------------

Append to 7.25.2.2.1#4:

If desc is zero, the iswctype function returns zero (false).

Append to 7.25.3.2.1#4:

If desc is zero, the towctrans function returns the value of wc.


====
Potential Defect Report 14

Subject: mbtowc and partial characters
-------

Problem
-------

If mbtowc() is given a partial character (or an escape sequence that
isn't a complete character), it returns -1. However, is it supposed to
remember the relevant state information or should it ignore it.

Consider an implementation where the character '\xE' starts an alternate
shift state and '\xF' returns to the initial shift state. The wide
character encodings are:

initial shift state: 'x' -> ASCII codes
alternate shift state: 'x' -> ASCII codes + 0x100

Starting in the initial shift state,

mbtowc (&wc, "\xEZ", 2);

should return 2 and set wc to 0x15A. However, starting in the initial
shift state, consider:

mbtowc (&wc1, "\xE", 1);
mbtowc (&wc2, "Z", 1);

I would expect that the first call returns -1, leaving wc1 unaltered,
while the second returns 1 and sets wc2 to 0x5A. However, is it
permitted for the second to set wc2 to 0x15A ? If so, how is an
application meant to use mbtowc ?

[The newer function mbrtowc does not have this problem.]


Suggested Technical Corrigendum
-------------------------------

Append to 7.20.7.2#2:

If the next multibyte character is incomplete or invalid, the
shift state is unaffected and nothing is stored.


====
Potential Defect Report 15

Subject: Editorial
-------

Problem
-------

In 7.20.7.2, the first paragraph of the Returns section does not have a
separate paragraph number.


====
Potential Defect Report 16

Subject: non-prototyped function calls and argument mismatches
-------

Problem
-------

Consider the code:

#include <stdio.h>

int f ();

int main (void)
{
return f (0);
}

#ifdef PROTO
int f (unsigned int x)
#else
int f (x) unsigned int x;
#endif
{
return printf ("%u\n", x);
}

Now, 6.5.2.2#6 reads:

[#6] If the expression that denotes the called function has
a type that does not include a prototype, the integer
promotions are performed on each argument, and arguments
that have type float are promoted to double. These are
called the default argument promotions.
[...]
If the function is defined with a
type that includes a prototype, and either the prototype
ends with an ellipsis (, ...) or the types of the arguments
after promotion are not compatible with the types of the
parameters, the behavior is undefined. If the function is
defined with a type that does not include a prototype, and
the types of the arguments after promotion are not
compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:

-- one promoted type is a signed integer type, the other
promoted type is the corresponding unsigned integer
type, and the value is representable in both types;

-- both types are pointers to qualified or unqualified
versions of a character type or void.

So the above code is undefined if PROTO is defined, but is legitimate if
it is not. This seems inconsistent.

Traditionally, when a function is called and no prototype is in scope,
the implementation applies the default argument promotions to the
argument value and then assumes that is the parameter type. If it isn't,
this can cause all kinds of problems, which is why the undefined
behaviour. However, if it is known that the argument value will be
correctly handled by the parameter type, there is no problem; this is
the rationale behind the exceptions.

The exceptions should apply to both cases, no matter how the function is
eventually defined.


Suggested Technical Corrigendum
-------------------------------

Change the part of 6.5.2.2#6 after the omission to:

If the types of the arguments after promotion are not
compatible with those of the parameters after promotion 78A),
the behavior is undefined, except for the following cases:

-- one promoted type is a signed integer type, the other
promoted type is the corresponding unsigned integer
type, and the value is representable in both types;

-- both types are pointers to qualified or unqualified
versions of a character type or void.

If the function is defined with a type that includes a
prototype, and either any parameter has a type which is altered
by the default argument promotions or the prototype ends with an
ellipsis (, ...), the behavior is undefined.

78A) Because of the rule later in this paragraph, it is only
necessary to check whether the parameter type undergoes promotion
when the function is not defined using a prototype.


====


--
Clive D.W. Feather, writing for himself | Home: <cl...@davros.org>
Tel: +44 20 8371 1138 (work) | Web: <http://www.davros.org>
Fax: +44 20 8371 4037 (D-fax) | Work: <cl...@demon.net>
Written on my laptop; please observe the Reply-To address

Jack Klein

unread,
Jun 15, 2001, 1:41:35 AM6/15/01
to
On Tue, 12 Jun 2001 16:00:08 +0100, "Clive D. W. Feather"
<cl...@on-the-train.demon.co.uk> wrote in comp.std.c:

> Potential Defect Report 12
>
> Subject: all-zero bits representations
> -------
>
> Problem
> -------
>
> Consider the code:
>
> int v [10];
> memset (v, 0, sizeof v);
>
> Most programmers would expect this code to set all the elements of v to
> zero. However, the code is actually undefined: it is possible for int to
> have a representation in which all-bits-zero is a trap representation
> (for example, if there is an odd-parity bit in the value).

I do not claim to be aware of all implementations that use parity, but
I have designed hardware for a few. All implementations with parity
that I know of keep the parity bit completely outside the view of the
processor hardware and therefore the C abstract machine.

Example, the original IBM PC 8088 versions with 8 bit data bus. A
separate IC (74S280, IIRC) generated the ninth bit from the 8 that the
processor read or wrote. The processor, and therefore the software
executing on the processor could neither read nor write the parity bit
directly.

> This problem applies to all integer types except for unsigned char. I
> believe that the idiom is well-enough known that it should be made a
> part of the Standard.
>
>
> Suggested Technical Corrigendum
> -------------------------------
>
> Append to 6.2.6.2#5:
>
> For any integer type, the object representation where all the
> bits are zero shall be a representation of the value zero in
> that type.
>

This would be an excellent change to make, always provided that there
are actually no non-extinct hardware platforms where it would break.

Padding and trap bits have rendered both calloc() and memset(ptr, 0,
size) in C99 useless for anything other than arrays of unsigned char.
It would be nice to have them back for all the integer types, as
before.

--
Jack Klein
Home: http://JK-Technology.Com

Jack Klein

unread,
Jun 15, 2001, 1:58:04 AM6/15/01
to
On Tue, 12 Jun 2001 16:00:08 +0100, "Clive D. W. Feather"
<cl...@on-the-train.demon.co.uk> wrote in comp.std.c:

> Potential Defect Report 16


>
> Subject: non-prototyped function calls and argument mismatches

[snip]

> -- one promoted type is a signed integer type, the other
> promoted type is the corresponding unsigned integer
> type, and the value is representable in both types;
>

[snip]

> Traditionally, when a function is called and no prototype is in scope,
> the implementation applies the default argument promotions to the
> argument value and then assumes that is the parameter type. If it isn't,
> this can cause all kinds of problems, which is why the undefined
> behaviour. However, if it is known that the argument value will be
> correctly handled by the parameter type, there is no problem; this is
> the rationale behind the exceptions.
>
> The exceptions should apply to both cases, no matter how the function is
> eventually defined.
>
>
> Suggested Technical Corrigendum
> -------------------------------
>
> Change the part of 6.5.2.2#6 after the omission to:
>
> If the types of the arguments after promotion are not
> compatible with those of the parameters after promotion 78A),
> the behavior is undefined, except for the following cases:
>
> -- one promoted type is a signed integer type, the other
> promoted type is the corresponding unsigned integer
> type, and the value is representable in both types;

[snip]

I have no problem agreeing with this, always provided there is no
existent hardware where it would not work.

Note that there is a footnote in the standard (16 in C90 and 32 in
C99) that says "The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions, return
values from functions, and members of unions".

I would suggest that this footnote be ammended at the very least to
change the words "are meant to imply" to "guarantee". Actually since
footnotes are not normative, it should be eliminated and such a
guarantee placed directly in the text.

Would this impact variadic functions? Up until now all of the
following have been technically undefined:

printf("%d\n", 3U);
printf("%u\n", -1);

Would this change render the calls above strictly conforming? If so,
should the wording of the descriptions for the *printf family be
changed?

Douglas A. Gwyn

unread,
Jun 15, 2001, 10:31:25 AM6/15/01
to
Jack Klein wrote:
> <cl...@on-the-train.demon.co.uk> wrote in comp.std.c:

> > int v [10];
> > memset (v, 0, sizeof v);
> > Most programmers would expect this code to set all the elements of v to
> > zero. However, the code is actually undefined: it is possible for int to
> > have a representation in which all-bits-zero is a trap representation
> > (for example, if there is an odd-parity bit in the value).
> I do not claim to be aware of all implementations that use parity, but
> I have designed hardware for a few. All implementations with parity
> that I know of keep the parity bit completely outside the view of the
> processor hardware and therefore the C abstract machine.

There have been processors where a parity bit was an accessible part
of the storage word; however, on the ones I know of it would not be
necessary nor advisable to include the parity bit within the "object
representation" (in the C standard's use of the term). The point is
that it *could* be, so there are ramifications for strict conformance.

> > Append to 6.2.6.2#5:
> > For any integer type, the object representation where all the
> > bits are zero shall be a representation of the value zero in
> > that type.
> This would be an excellent change to make, always provided that there
> are actually no non-extinct hardware platforms where it would break.

One also needs to consider reasonable future architectures.

> Padding and trap bits have rendered both calloc() and memset(ptr, 0,
> size) in C99 useless for anything other than arrays of unsigned char.
> It would be nice to have them back for all the integer types, as
> before.

Actually, padding as such should be benign; it's trap bits that are
troublesome. I would like to carefully revisit the whole issue.

Clive D. W. Feather

unread,
Jun 15, 2001, 11:43:10 AM6/15/01
to
In article <mg7jit0a897ge8aep...@4ax.com>, Jack Klein
<jack...@spamcop.net> writes

>> Most programmers would expect this code to set all the elements of v to
>> zero. However, the code is actually undefined: it is possible for int to
>> have a representation in which all-bits-zero is a trap representation
>> (for example, if there is an odd-parity bit in the value).
>
>I do not claim to be aware of all implementations that use parity, but
>I have designed hardware for a few. All implementations with parity
>that I know of keep the parity bit completely outside the view of the
>processor hardware and therefore the C abstract machine.

You may well be right. It nevertheless makes a convenient example.

>> For any integer type, the object representation where all the
>> bits are zero shall be a representation of the value zero in
>> that type.
>
>This would be an excellent change to make, always provided that there
>are actually no non-extinct hardware platforms where it would break.

I'm not aware of any, but I'd be interested to learn otherwise.

Clive D. W. Feather

unread,
Jun 15, 2001, 11:48:22 AM6/15/01
to
In article <638jitg0n15mpdnba...@4ax.com>, Jack Klein
<jack...@spamcop.net> writes

>I have no problem agreeing with this, always provided there is no
>existent hardware where it would not work.

There shouldn't be: if the compiler can make it work in one case, it can
make it work in the other.

>Note that there is a footnote in the standard (16 in C90 and 32 in
>C99) that says "The same representation and alignment requirements are
>meant to imply interchangeability as arguments to functions, return
>values from functions, and members of unions".

Yes, but that's a hint and has no force.

>I would suggest that this footnote be ammended at the very least to
>change the words "are meant to imply" to "guarantee". Actually since
>footnotes are not normative, it should be eliminated and such a
>guarantee placed directly in the text.

This was rejected (I proposed it) during the C99 process. I didn't get a
feel for why people objected to it.

>Would this impact variadic functions?

No: the same exception is already in 7.15.1.1.

>Up until now all of the
>following have been technically undefined:
>
>printf("%d\n", 3U);
>printf("%u\n", -1);
>
>Would this change render the calls above strictly conforming?

No.

>If so,
>should the wording of the descriptions for the *printf family be
>changed?

The first of your examples ought to be legal; the second is more
arguable.

Joseph S. Myers

unread,
Jun 15, 2001, 3:32:23 PM6/15/01
to
In article <Xb0HFCE4...@romana.davros.org>,

Clive D. W. Feather <cl...@davros.org> wrote:
>Potential Defect Report 9
>
>Subject: are "struct fred" and "union fred" the same type ?

>I can see nothing that forbids this code. In particular, 6.7.2.3#8

I can see nothing that explicitly says that "struct" is used to
declare structures, and "union" to declare unions (though the examples
show some cases of "struct" declaring structures, they don't say that
struct { ... } never declares a union, nor union { ... } a structure).
They are treated together in 6.7.2.1 (though enums are treated
separately). Perhaps the solution is to add a constraint to say that
"struct" specifies structure types, and shall not be used in a
specifier for a non-structure type, and similarly for "union" and
"enum"?

--
Joseph S. Myers
js...@cam.ac.uk

0 new messages