Suffix allowed on expressions?

D

dspfun

Hi!

Are suffixes allowed on expressions?

For example, is the following allowed:

#define SECONDS_PER_YEAR (60 * 60 * 365) UL

I found this in a C test at http://www.embedded.com/2000/0005/0005feat2.htm
,
however, I am not able to compile when using this macro (or just the
expression "a = (60 * 60 * 365) UL;").

Where in the standard does it say that it is allowed/not allowed?

It would also be interesting to hear if there are any faults in the
other questions and answers in the test.

BRs!
 
B

Ben Pfaff

dspfun said:
Are suffixes allowed on expressions?

No. The suffixes that you are talking about are allowed only on
integer and floating-point constants.
For example, is the following allowed:

#define SECONDS_PER_YEAR (60 * 60 * 365) UL

No. To get the apparently intended effect, you can write
#define SECONDS_PER_YEAR (60UL * 60 * 365)
or
#define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)
 
B

Ben Pfaff

Ben Pfaff said:
To get the apparently intended effect, you can write
#define SECONDS_PER_YEAR (60UL * 60 * 365)
or
#define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)

Oh, and to get the apparently intended value, you need to
multiply by an additional factor of 24.
 
D

dspfun

Hi!

Are suffixes allowed on expressions?

For example, is the following allowed:

#define SECONDS_PER_YEAR (60 * 60 * 365) UL

It should be:
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365) UL
I found this in a C test athttp://www.embedded.com/2000/0005/0005feat2.htm
,
however, I am not able to compile when using this macro (or just the
expression "a = (60 * 60 * 365) UL;").

It should be:
(or just the expression statement "a = (60 * 60 * 24 * 365) UL;")
 
B

Ben Bacarisse

Ben Pfaff said:
No. To get the apparently intended effect, you can write
#define SECONDS_PER_YEAR (60UL * 60 * 365)
or
#define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)

The latter can, as I am sure you know, overflow. Since the quiz was
on a site that referenced embedded systems, it would be safer to
assume a minimal max int (if you see what I mean).

To the OP: to illustrate using a cast (which *can* be used in
expressions unlike suffixes) you could write:

#define SECONDS_PER_YEAR ((unsigned long int)60 * 60 * 365)

* is left-associative so all the multiplications must produce unsigned
long int results.
 
K

Keith Thompson

dspfun said:
Are suffixes allowed on expressions?

No (unless the expression happens to be an integer constant).
For example, is the following allowed:

#define SECONDS_PER_YEAR (60 * 60 * 365) UL
Nope.

I found this in a C test at
http://www.embedded.com/2000/0005/0005feat2.htm , however, I am not
able to compile when using this macro (or just the expression "a =
(60 * 60 * 365) UL;").

Where in the standard does it say that it is allowed/not allowed?

Suffixes such as UL are described in C99 6.4.4.1, "Integer constants"
(and similar suffixes are described in 6.4.4.2, "Floating constants").
The fact that they aren't described anywhere else, particularly the
fact that the grammar permits them only in those contexts, implies
that they aren't permitted anywhere else. (There's no need to state
that they're not allowed.)
It would also be interesting to hear if there are any faults in the
other questions and answers in the test.

Some of the code layout is messed up, at least in my browser. In some
cases, lines are split before and after '<' characters. I'd guess
this isn't the author's fault.

As you say, he completely messed up on the first question. Failing to
compile code to be used in a published article is a *big* mistake.

In question 8 about the volatile keyword, he says that the variable
can be changed unexpectedly, but he fails to mention that when the
*program* changes a volatile variable, the new value must actually be
stored rather than cached. He covers the implications for reading the
variable, but not for writing it. (The latter is a constraint on the
implementation, not on the programmer, so perhaps that's excusable.)

In question 14, he needlessly casts the result of malloc(). Worse
than that, he's mistaken about the actual point of the question, the
result of malloc(0). He says, or strongly implies, that malloc(0)
always returns a valid (non-null) pointer. In fact, it's
implementation-defined whether malloc(0) returns a null pointer or a
unique non-null pointer.

Question 15 asks which of these is preferred:

#define dPS struct s *
typedef struct s * tPS;

as a way to define an alias for a pointer to type "struct s". Apart
from failing to mention the inadvisability of aliasing a pointer type,
he gets the asnwer right, but his attitude here is odd to the point
of being wrong:

This is a very subtle question, and anyone who gets it right (for
the right reason) is to be congratulated or condemned ("get a
life" springs to mind).

The problem, of course, is with declarations like:

dPS p1, p2;
tPS p3, p4;

But this isn't a remarkably obscure point, as he implies; it's
something that every C programmer should know.

There's a contact address in the article; I'll send him pointers to
your article and my followup.
 
K

Keith Thompson

Keith Thompson said:
There's a contact address in the article; I'll send him pointers to
your article and my followup.

The e-mail address in the article is obsolete (I think the article is
several years old). I found what appears to be his current address by
searching the embedded.com web site. (I won't post it here; I'm sure
he gets more than enough spam already.)
 
C

CBFalconer

Ben said:
No. The suffixes that you are talking about are allowed only on
integer and floating-point constants.


No. To get the apparently intended effect, you can write
#define SECONDS_PER_YEAR (60UL * 60 * 365)
or
#define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)

The second will only work if the expression (60 * 60 * 365) is
within the range of an int. This is doubtful if running on a 16
bit system.
 
D

dspfun

What about question 12, isn't it implementation specific since the
representation of the basic types are not precisely defined by the
language?

---------------
12. What does the following code output and why?

void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}

Answer:
This question tests whether you understand the integer promotion rules
in C-an area that I find is very poorly understood by many developers.
Anyway, the answer is that this outputs "> 6." The reason for this is
that expressions involving signed and unsigned types have all operands
promoted to unsigned types. Thus ý20 becomes a very large positive
integer and the expression evaluates to greater than 6. This is a very
important point in embedded systems where unsigned data types should
be used frequently (see Reference 2). If you get this one wrong, you
are perilously close to not getting the job.
-------------
 
R

Richard Heathfield

dspfun said:
It should be:
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365) UL

The result of the above calculation will be out by 86400 seconds this year.
 
J

jameskuyper

dspfun said:
What about question 12, isn't it implementation specific since the
representation of the basic types are not precisely defined by the
language?

This has nothing to do with the representation of the basic types, it
depends only upon the usual arithmetic conversions. While the results
of those conversions vary from implementation to implementation, the
particular values chose for a and b below are guaranteed to produce
the same final results on all conforming implementations of C.
---------------
12. What does the following code output and why?

void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}

Answer:
This question tests whether you understand the integer promotion rules
in C-an area that I find is very poorly understood by many developers.
Anyway, the answer is that this outputs "> 6." The reason for this is
that expressions involving signed and unsigned types have all operands
promoted to unsigned types. ...

Note that this is not the correct rule in C99, though I think it's a
correct statement of the C90 rule. In C99, the signed operand is
converted to the type of the unsigned operand only if the rank of the
unsigned type is greater than or equal to the rank of the signed type.
In this case, that happens to be true.
... Thus �20 becomes a very large positive
integer and the expression evaluates to greater than 6. ...

Specifically, (a+b) has a value of UINT_MAX-13. The value of that sum
depends upon the implementation, since UINT_MAX depends upon the
implementation. However, since UINT_MAX must be at least 65535, that
value is guaranteed to be at least 65522, and therefore greater than
6, and the routine is guaranteed to pass "> 6" to puts().
 
J

jameskuyper

Richard said:
dspfun said:


The result of the above calculation will be out by 86400 seconds this year.

On the originally referenced web site, the relevant question specified
that leap years are to be ignored. The macro name should have
reflected that fact, though I'm not sure of the best way to do so.
SECONDS_PER_NON_LEAP_YEAR?
 
D

dspfun

This has nothing to do with the representation of the basic types, it
depends only upon the usual arithmetic conversions. While the results
of those conversions vary from implementation to implementation, the
particular values chose for a and b below are guaranteed to produce
the same final results on all conforming implementations of C.







Note that this is not the correct rule in C99, though I think it's a
correct statement of the C90 rule. In C99, the signed operand is
converted to the type of the unsigned operand only if the rank of the
unsigned type is greater than or equal to the rank of the signed type.
In this case, that happens to be true.


Specifically, (a+b) has a value of UINT_MAX-13. The value of that sum
depends upon the implementation, since UINT_MAX depends upon the
implementation. However, since UINT_MAX must be at least 65535, that
value is guaranteed to be at least 65522, and therefore greater than
6, and the routine is guaranteed to pass "> 6" to puts().- Dölj citerad text -

- Visa citerad text -

Ok, thank you for the explanation! I believe it is the following in
C99 that specifies this (that the result of a+b will be UINT_MAX + 1
-20 + 6 = UINT_MAX-13):

2
Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or
subtracting one more than the maximum value that can be represented in
the new type
until the value is in the range of the new type.49)
 
C

CBFalconer

.... snip ...

On the originally referenced web site, the relevant question
specified that leap years are to be ignored. The macro name
should have reflected that fact, though I'm not sure of the
best way to do so. SECONDS_PER_NON_LEAP_YEAR?

Too long. Try SECS_PER_SQUAT_YR. :)
 
A

Army1987

Keith said:
No (unless the expression happens to be an integer constant).
The suffix is *part* of the constant. They form one token.
You can't have e.g. `12 UL`.
 
C

Charles Richmond

CBFalconer said:
The second will only work if the expression (60 * 60 * 365) is
within the range of an int. This is doubtful if running on a 16
bit system.

And SECONDS_PER_YEAR really is equal to (60 * 60 * 24 * 365).
^^^^
 
D

dspfun

How about question 7, is it correct (referring to the test in the link
at the top of the thread)? :

int const * a const;

The declaration above doesn't compile using gcc.
 
J

jameskuyper

dspfun said:
How about question 7, is it correct (referring to the test in the link
at the top of the thread)? :

int const * a const;

The declaration above doesn't compile using gcc.

'const' is a type-qualifier, and therefore a declaration-specifier.
'a' is parsed as a direct-declarator, and therefore as a declarator,
and therefore as an init-declarator-list. 6.7p1 requires that
declarations-specifiers preceed the init-declarator-list, so this is
an incorrect declaration.
 
D

dspfun

'const' is a type-qualifier, and therefore a declaration-specifier.
'a' is parsed as a direct-declarator, and therefore as a declarator,
and therefore as an init-declarator-list. 6.7p1 requires that
declarations-specifiers preceed the init-declarator-list, so this is
an incorrect declaration.

Thanks for a great answer!

How did you do the mapping type-qualifier -> declaration-specifier and
direct-declarator -> declarator -> init-declarator-list ?

I found something more suspicuous in the anser to question 2:

"Knowledge of the ternary conditional operator. This operator exists
in C because it allows the compiler to produce more optimal code than
an if-then-else sequence. "

Is this really true?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top