Please take a look at the code below
and tell me what's wrong with it.
Someone told me to check the compiler.
The compiler I use is gcc.
(could you please let me know the options necessary ?)
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void f(int xx, int yy, int aa[xx][yy]);
int main()
{
int x = 2 ;
int y = 3 ;
int a[x][y];
f(x,y,a) ;
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
}
}
return 0;
}
void f(int xx, int yy, int aa[xx][yy]){
for( int i=0;i<xx;i++){
for( int j=0;j<yy;j++){
*(*(aa+i)+j) = i+10*j ;
}
}
}
> int x = 2 ;
> int y = 3 ;
> int a[x][y];
You can't do that, if x and y are meant to be constant values then
declare them as constants, then you can use them in the declaration of
the array.
But if I guess from the subject of your message you want the x and y to
be variables, if so you must allocate the array dynamically
int i;
int **a;
*a = malloc(x * sizeof(int*));
for(i=0; i<x; i++) {
a[i] = malloc(y * sizeof(int));
}
>
> f(x,y,a) ;
>
> for(int i=0;i<x;i++){
This is not valid either (not sure if it is with C99) declare the at the
begining of main with the other variables... are you compiling this with
a C++ compiler instead of a C compiler? make sure you don't.
> printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
What was that supposed to do?
> void f(int xx, int yy, int aa[xx][yy]){
if you want to pass a 2d array to the function just do:
void f(int xx, int yy, int **aa)
Also am I guessing correctly that you use these weird names for your
variables because you somehow think that the names will colide with the
x, y and a in your main function ?... well that's not so, you may use x
y and a here as well.
-- Nuclear / the Lab --
Compile it with gcc -Wall -std=c99 -pedantic whatever.c
Note that the C99 support is not complete yet in gcc.
> Thanks in advance.
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <math.h>
>
> void f(int xx, int yy, int aa[xx][yy]);
>
> int main()
> {
>
> int x = 2 ;
> int y = 3 ;
> int a[x][y];
>
> f(x,y,a) ;
>
> for(int i=0;i<x;i++){
> for(int j=0;j<y;j++){
> printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
This is wrong. The type of *(*(a+i)+j) is int but the corresponding
conversion specifier (%10.0f) is expecting an argument of type double.
You should replace the "%10.0f" with "%d". You could also write a[i][j]
instead of *(*(a+i)+j)).
Your program has some basic errorrs.Compare your program with
following program.It works
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void f(int xx, int yy, int aa[xx][yy]);
int main()
{
int x = 2 ;
int y = 3 ;
int a[x][y];
int i,j;
f(x,y,a) ;
for(i=0;i<x;i++){
for(j=0;j<y;j++){
printf("a[%2d][%2d] is %d\n",i,j,*(*(a+i)+j));
}
}
return 0;
}
void f(int xx, int yy, int aa[xx][yy]){
int i,j;
for( i=0;i<xx;i++){
for( j=0;j<yy;j++){
*(*(aa+i)+j) = i+10*j ;
}
}
}
GCC does not support variable length arrays correctly.
See http://gcc.gnu.org/c99status.html for more info.
Specifically,
"The C99 semantics of variable length arrays (VLAs) are not
fully implemented by the existing GCC extension: the
concept of variably modified (VM) types, and the rules for
what identifiers can be declared with VLA or VM types, are
not implemented (for example, GCC allows elements of VM
type in a structure with block scope); while the syntax
for arrays to be declared with [*] in parameter
declarations is present, the semantics are not; and in
general the implementation of VLAs has not been checked
against C99 requirements."
> (could you please let me know the options necessary ?)
I'd recommend
gcc -std=c99 -pedantic -Wall -W -O2 filename.c -o filename -lm
This sets gcc in pedantic C99 mode, displaying most warnings,
even more warnings, optimisation (which also turns on the
variable use warnings), and link in the math library (if
necessary on your platform).
I find it very helpful to have the compiler give me that many
warnings, but it is only useful if you actually work out each
one and fix the code properly. (And not just add casts until
it shuts up!) I very rarely use casts in my programming; one
exception is for printing size_t values, since my standard
library implementation doesn't support the "%zu" conversion
specifier yet, I still do printf("%lu", (long unsigned)value);
> #include <stdio.h>
> #include <stdlib.h>
> #include <math.h>
>
> void f(int xx, int yy, int aa[xx][yy]);
>
> int main()
> {
> int x = 2 ;
> int y = 3 ;
> int a[x][y];
>
> f(x,y,a) ;
>
> for(int i=0;i<x;i++){
> for(int j=0;j<y;j++){
> printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
PLEASE use normal array syntax. *(*(a+i)+j) is equivalent
to a[i][j] and the latter is much easier to read.
As others have pointed out, the conversion specifier does
not match the type passed in; this is undefined behaviour,
and in fact it is pointed out by gcc if you enable the
warnings like I suggested above:
vlatest.c:19: warning: double format, different type arg (arg 4)
> }
> }
> return 0;
> }
>
> void f(int xx, int yy, int aa[xx][yy]){
> for( int i=0;i<xx;i++){
> for( int j=0;j<yy;j++){
> *(*(aa+i)+j) = i+10*j ;
Again,
aa[i][j] = i + 10 * j;
is exactly the same, but much clearer.
> }
> }
> }
--
Simon.
>Jonghoon Ryu wrote:
>
>> int x = 2 ;
>> int y = 3 ;
>> int a[x][y];
>
>You can't do that, if x and y are meant to be constant values then
>declare them as constants,
How do you do that in C?
>then you can use them in the declaration of the array.
>But if I guess from the subject of your message you want the x and y to
>be variables, if so you must allocate the array dynamically
>
>int i;
>int **a;
>*a = malloc(x * sizeof(int*));
>for(i=0; i<x; i++) {
> a[i] = malloc(y * sizeof(int));
>}
His subject line clearly means that he wants variable length arrays, not
dynamically allocated arrays.
>> f(x,y,a) ;
>>
>> for(int i=0;i<x;i++){
>
>This is not valid either (not sure if it is with C99) declare the at the
>begining of main with the other variables... are you compiling this with
>a C++ compiler instead of a C compiler? make sure you don't.
Both features are either valid (C99) or invalid (C89).
By writing the code the way he did, he's limiting it to conforming C99
implementations (*extremely* few and far between) or to compilers
supporting these features as extensions. Neither feature can be currently
used for portable programming purposes.
Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan...@ifh.de
>Please take a look at the code below
>and tell me what's wrong with it.
>
>Someone told me to check the compiler.
>The compiler I use is gcc.
>(could you please let me know the options necessary ?)
Compiler related questions usually belong to compiler related newsgroups.
Furthermore, the answer also depends on your gcc version.
>#include <stdio.h>
>#include <stdlib.h>
What for?
>#include <math.h>
What for?
>void f(int xx, int yy, int aa[xx][yy]);
Define f here and this declaration becomes pointless. This is more than
a style issue, it is also a maintainability issue (if you change the
function's interface, you have to do it in two places).
>int main()
>{
>
> int x = 2 ;
> int y = 3 ;
> int a[x][y];
>
> f(x,y,a) ;
>
> for(int i=0;i<x;i++){
> for(int j=0;j<y;j++){
> printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
^^^^^^ ^^^^^^^^^^^
A plain -Wall option would have told you that that your format string
is broken, but you didn't bother.
Besides, there is no point in writing *(*(a+i)+j) instead of the
straightforward, a[i][j].
> }
> }
>
> return 0;
>}
>
>void f(int xx, int yy, int aa[xx][yy]){
> for( int i=0;i<xx;i++){
> for( int j=0;j<yy;j++){
> *(*(aa+i)+j) = i+10*j ;
> }
> }
>}
I would strongly recommend to stay away from the C99 features, until you
have mastered C89, the language currently implemented by the available
compilers and described by the tutorial books. That way, you don't have
to ask what esoteric options are needed for compiling your code and you
have a chance to compile it with *any* mainstream compiler, rather then
being tied to certain versions of a certain compiler.
> Hi, all,
>
> Please take a look at the code below
> and tell me what's wrong with it.
>
> Someone told me to check the compiler.
That's right: always blame the compiler for your mistakes.
> int y = 3 ;
> int a[x][y];
> printf("a[%2d][%2d] is %10.0f\n",i,j,*(*(a+i)+j));
The '*(*(a+i)+j)' is just removing the syntactic sugar from the easier
to read 'a[i][j]', which is an int. Using a floating point specifier
'%10.0f' to print an int has no meaning.
--
Martin Ambuhl
now exiled to
Hurricane Bait, Texas
>I'd recommend
> gcc -std=c99 -pedantic -Wall -W -O2 filename.c -o filename -lm
A better choice (unless generating the final production binaries) is
gcc -std=c99 -pedantic -Wall -O
-W triggers often undesirable warnings (that's why they haven't been
included in -Wall in the first place) and -O2 slows down the compilation
with no redeeming benefits during the development phase. -O is enough for
-Wall to do everything it can do.
OTOH, I would highly recommend newbies to stay away from -std=c99 and
use -ansi instead. They have a lot more important things to learn than
the *exact* effects of -std=c99.
C89 or C99? :)
in C89 with a #define
in C99 I think you can do it the C++ way, with const and still being
able to use it for a fixed array size not really sure though since I am
not terribly familliar with C99 changes right now.
>
>
>>then you can use them in the declaration of the array.
>>But if I guess from the subject of your message you want the x and y to
>>be variables, if so you must allocate the array dynamically
>>
>>int i;
>>int **a;
>>*a = malloc(x * sizeof(int*));
>>for(i=0; i<x; i++) {
>> a[i] = malloc(y * sizeof(int));
>>}
>
>
> His subject line clearly means that he wants variable length arrays, not
> dynamically allocated arrays.
I don't think he meant that by seeing his code, I believe that he just
used wrong terminology in the topic... however ok if you want it that
way, realloc to your heart's content :)
(I would probably make a Resize() function that handles that since we
are talking about a 2d array, to avoid much hassle in the code)
The warnings triggered by -W are often more stylistic things,
or reminders that some practise may be a bit dangerous in some
situations (even if in the specific case it is actually correct).
I quite like those warnings, and prefer to modify my code to work
around them rather than disable them, wherever possible.
-W Print extra warning messages for these events:
# -o- A function can return either with or without a value.
# (Falling off the end of the function body is considered
# returning without a value.) For example, this function
# would evoke such a warning:
#
# foo (a)
# {
# if (a > 0)
# return a;
# }
I like this warning, it usually analyses the flow correctly
and there really is a possibility of falling off the end
without returning a value. If I know that the data is such
that I won't fall off the end, I think it's better to make
that explicit in the code.
# -o- An expression-statement or the left-hand side of a comma
# expression contains no side effects. To suppress the
# warning, cast the unused expression to void. For example,
# an expression such as x[i,j] will cause a warning, but
# x[(void)i,j] will not.
This is quite useful, as it lets you know if you have
inadvertently used the comma operator. There is no point
evaluating an expression without side effects then throwing
away its value.
# -o- An unsigned value is compared against zero with < or <=.
Since an unsigned value can never be less than zero, this warning
indicates a design error.
# -o- A comparison like x<=y<=z appears; this is equivalent to
# (x<=y ? 1 : 0) <= z, which is a different interpretation
# from that of ordinary mathematical notation.
I've never got this warning, but I don't consider it a problem,
either. If I really did want to do the comparison against 0 or 1
I would write it out more clearly as an aid to future readers of
the code.
# -o- Storage-class specifiers like static are not the first
# things in a declaration. According to the C Standard,
# this usage is obsolescent.
Nothing wrong with warning about obsolescent features.
# -o- The return type of a function has a type qualifier such
# as const. Such a type qualifier has no effect, since the
# value returned by a function is not an lvalue. (But
# don't warn about the GNU extension of volatile void
# return types. That extension will be warned about if
# -pedantic is specified.)
Again would indicate a design error.
# -o- If -Wall or -Wunused is also specified, warn about unused
# arguments.
This is very useful, as unused arguments are almost always a
design error.
# -o- A comparison between signed and unsigned values could
# produce an incorrect result when the signed value is
# converted to unsigned. (But don't warn if
# -Wno-sign-compare is also specified.)
This one forced me to change the type of anything that's
compared against size_t, so they are all size_t values. I'm
now in the habit of doing that, and I think it's better that
way. Looping through an array makes most sense in size_t as
it is not arbitrarily restricted.
# -o- An aggregate has a partly bracketed initializer. For
# example, the following code would evoke such a warning,
# because braces are missing around the initializer for x.h:
#
# struct s { int f, g; };
# struct t { struct s h; int i; };
# struct t x = { 1, 2, 3 };
Although it's stylistic, I agree with the suggestion as the
code is clearer to read when initialisers are fully bracketed.
However this warning together with the next one can be annoying.
# -o- An aggregate has an initializer which does not initialize
# all members. For example, the following code would cause
# such a warning, because x.h would be implicitly initialized
# to zero:
#
# struct s { int f, g, h; };
# struct s x = { 3, 4 };
I would like to be able to use the initialiser
= {0}
as a catch-all to initialise any aggregate to 0.
For example:
struct s {int a; int b; int c;};
struct s foo = {0};
warning: missing initializer
warning: (near initialization for `foo.b')
int bar[3][4] = {0};
warning: missing braces around initializer
warning: (near initialization for `bar[0]')
--
Simon.
I prefer
CFLAGS += \
-std=c99 -pedantic -Wall \
-W \
-Wundef \
-Wshadow \
-Wpointer-arith \
-Wbad-function-cast \
-Wcast-qual \
-Wcast-align \
-Wno-sign-compare \
-Waggregate-return \
-Wstrict-prototypes \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wredundant-decls \
-Wnested-externs \
-Winline \
-Wdisabled-optimization \
IMO enabling the above warnings does more good than harm, but some
of gcc's warnings are a nuisance, or even broken or buggy.
> -W Print extra warning messages for these events:
>
> # -o- A comparison like x<=y<=z appears; this is equivalent to
> # (x<=y ? 1 : 0) <= z, which is a different interpretation
> # from that of ordinary mathematical notation.
>
> I've never got this warning, but I don't consider it a problem,
> either. If I really did want to do the comparison against 0 or 1
> I would write it out more clearly as an aid to future readers of
> the code.
This is an example where gcc gets it wrong. I recently got this warning
and had to throw in parentheses at random places to shut gcc up. This
made the code *less* easy to understand. All because I used the, for me
at least, standard idiom b1 == b2 == ... == bn (which says that an
even (odd) number of the boolean expressions are true if n is even (odd);
parentheses can be placed arbitrary). The reason gcc gives for warning
about this construct doesn't carry much weight since we are not in a
math context. Has anyone really received this warning and benefited from
it?
A similar example is gcc's depreciation of use of the fact that && has
higher precedence than ||. Here it's even harder to understand the reason
for the warning. For the &&-|| warning to be beneficial you would have to
first not know the precedences of && and || and then assume some wrong
precedence! One could almost just as well warn about uses of the fact
that * has higher precedence than +.
One could at least expect separate flags for the cases where gcc moves
away from common practice and idioms.
> # -o- If -Wall or -Wunused is also specified, warn about unused
> # arguments.
>
> This is very useful, as unused arguments are almost always a
> design error.
And in the rare case where it's not a design error you can use something
like:
#ifdef __GNUC__
#define attribute__(a) __attribute__ ((a))
#else
#define attribute__(a)
#endif
int f( void * dummy attribute__(unused) )
{
return 0;
}
Daniel Vallstrom
>>>You can't do that, if x and y are meant to be constant values then
>>>declare them as constants,
>>
>>
>> How do you do that in C?
>
>C89 or C99? :)
>in C89 with a #define
Last time I checked, #define defined preprocessor macros, not constants.
>in C99 I think you can do it the C++ way, with const and still being
>able to use it for a fixed array size not really sure though since I am
>not terribly familliar with C99 changes right now.
Let's see:
fangorn:~/tmp 274> cat test.c
const int foo = 3;
int a[foo];
fangorn:~/tmp 275> gcc -c -std=c99 test.c
test.c:2: variable-size type declared outside of any function
fangorn:~/tmp 276> gcc -c -ansi test.c
test.c:2: variable-size type declared outside of any function
It doesn't appear that the semantics of const have changed between C89
and C99... And if you're not terribly familiar with something, it's
much wiser to avoid talking about that something. As you can see, it was
a no-brainer to invalidate your assertion.
BTW, if the type is int, there is a proper way of defining a constant in C
fangorn:~/tmp 279> cat test.c
enum {foo = 3};
int a[foo];
fangorn:~/tmp 280> gcc -c -ansi -pedantic test.c
fangorn:~/tmp 281>
>>>then you can use them in the declaration of the array.
>>>But if I guess from the subject of your message you want the x and y to
>>>be variables, if so you must allocate the array dynamically
>>>
>>>int i;
>>>int **a;
>>>*a = malloc(x * sizeof(int*));
>>>for(i=0; i<x; i++) {
>>> a[i] = malloc(y * sizeof(int));
>>>}
>>
>>
>> His subject line clearly means that he wants variable length arrays, not
>> dynamically allocated arrays.
>
>I don't think he meant that by seeing his code, I believe that he just
>used wrong terminology in the topic...
On the contrary, the subject line was perfectly consistent with his code.
Do you have the slightest clue about VLAs?
>"Dan Pop" <Dan...@cern.ch> wrote:
>> -W triggers often undesirable warnings (that's why they
>> haven't been included in -Wall in the first place)
>
>The warnings triggered by -W are often more stylistic things,
>or reminders that some practise may be a bit dangerous in some
>situations (even if in the specific case it is actually correct).
>I quite like those warnings, and prefer to modify my code to work
>around them rather than disable them, wherever possible.
I find them a nuisance and see no good reason for working around them.
The following is a trivial example where the compiler should trust the
programmer:
fangorn:~/tmp 336> cat test.c
#include <string.h>
void foo(int arg)
{
int i;
for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
}
fangorn:~/tmp 337> gcc -c -Wall test.c
fangorn:~/tmp 338> gcc -c -Wall -W test.c
test.c: In function `foo':
test.c:6: warning: comparison between signed and unsigned
test.c:3: warning: unused parameter `arg'
I can see NO good reason for doing something with arg to keep -W silent
and I cannot drop it from the function interface (which is externally
imposed). Likewise, I don't want to declare i as unsigned for the *sole*
reason of shutting up -W (or cast the return value of strlen). I only
use unsigned variables when I have a good reason for that, because of
reasons discussed in a different thread.
It's too bad it's illegal to omit the identifier in such cases.
Given that, I agree the warning is annoying in this case.
But an externally imposed function interface that requires
useless parameters is arguably the real cause of this particular
annoyance.
> Likewise, I don't want to declare i as unsigned for the *sole*
> reason of shutting up -W (or cast the return value of strlen).
> I only use unsigned variables when I have a good reason for
> that, because of reasons discussed in a different thread.
Your strlen usage example is perhaps too academic. The following
is equivalent, and evinces no such warning:
void foo(int arg)
{
int i;
for (i = 0; i < 5; i++) /* do something */ ;
}
--
Neil Cerutti
I don't see how Dan's example is academic or how yours is less academic.
sizeof array / sizeof *array
from my point of view is a somewhat often used term especially in for
or while loops which yields a unsigned integral value and comparing i
against it issues the warning Dan showed. I certainly do have a lot of
such comparisons in my programs and often either cast or declare i as
unsigned only for that reason.
--
Z (Zoran....@daimlerchrysler.com)
"LISP is worth learning for the profound enlightenment experience
you will have when you finally get it; that experience will make you
a better programmer for the rest of your days." -- Eric S. Raymond
I didn't intend to show a better example.
Here's a slightly less trivial example, that allows me to make my
point:
void foo(int arg, char *s)
{
int i; /* wrong */
for (i = 0; i < strlen(s); ++i) do_something(s[i]);
}
Using this example, it becomes possible to say that i ought to be
of type size_t, making it's range equal to strlen's range.
--
Neil Cerutti
<snip>
>
> Here's a slightly less trivial example, that allows me to make my
> point:
>
> void foo(int arg, char *s)
> {
> int i; /* wrong */
> for (i = 0; i < strlen(s); ++i) do_something(s[i]);
> }
>
> Using this example, it becomes possible to say that i ought to be
> of type size_t, making it's range equal to strlen's range.
And so it should. But don't you think it's better to move the strlen out of
the loop?
--
Richard Heathfield : bin...@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Yes.
--
Neil Cerutti
Actually, it's better to remove strlen completely:
for( i = 0; s[i]; i++ )
do_something(s[i]);
karl m
There is very good reason for the warning here as it has
uncovered a potential bug in your code. If the value
returned by strlen is greater than INT_MAX, your program
has undefined behaviour due to overflow.
You should always use size_t for loop iterators whose bound
is expressed in size_t. This includes arrays when you use
sizeof foo / sizeof *foo
as the bound.
> test.c:3: warning: unused parameter `arg'
>
> I can see NO good reason for doing something with arg to keep
> -W silent and I cannot drop it from the function interface
> (which is externally imposed).
In my experience externally imposed interfaces are uncommon,
and I see the odd cast to void as useful self-documentation.
It lets the reader of the code immediately see that you
intentially do not use the value of the argument.
> Likewise, I don't want to declare i as unsigned for the
> *sole* reason of shutting up -W (or cast the return value
> of strlen). I only use unsigned variables when I have a
> good reason for that, because of reasons discussed in a
> different thread.
But there is a very good reason to use a size_t variable here!
So, I would write:
#include <string.h>
void foo(int arg)
{
(void)arg;
for (size_t i = 0, n = strlen("abcde"); i < n; i++)
{
/* do something */
}
}
for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
gives no warnings.
--
Simon.
I don't see any potential for overflow in the above code.
As strlen returns a size_t which definitly is a unsigned integer type
and i is of signed int some conversion will take place. If size_t where
lower in rank than int (I'm not entirely sure about whether it would be
allowed to be lower in rank than int) the size_t value would be
converted to an int due to usual arithmetic conversions if all values of
size_t could be represented within int. If not, both values would be
converted to unsigned int and even if i where negativ overflow would not
occur.
If size_t is bigger in rank than i will equally be converted to the same
type and again overlfow can not happen. So I conclude there is no
potential fro overflow and thereby UB in this code.
But probably I've missed something.
> >> fangorn:~/tmp 336> cat test.c
> >> #include <string.h>
> >>
> >> void foo(int arg)
> >> {
> >> int i;
> >> for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
> >> }
> I don't see any potential for overflow in the above code.
> As strlen returns a size_t which definitly is a unsigned integer type
> and i is of signed int some conversion will take place. If size_t where
> lower in rank than int (I'm not entirely sure about whether it would be
> allowed to be lower in rank than int) the size_t value would be
> converted to an int due to usual arithmetic conversions if all values of
> size_t could be represented within int. If not, both values would be
> converted to unsigned int and even if i where negativ overflow would not
> occur.
>
> If size_t is bigger in rank than i will equally be converted to the same
> type and again overlfow can not happen. So I conclude there is no
> potential fro overflow and thereby UB in this code.
Apart from the fact that strlen ("abcde") is five and no overflow can
happen, if "abcde" were replaced by a string with 33000 characters and
int = 16 bit then the i++ will eventually overflow.
But I suspect the compiler complains about the fact that if i is
negative (which it can't be in this example) then i is less than strlen
("abcde") but (i < strlen ("abcde")) could produce a result of zero.
Strictly according to the C rules, but wrong.
The overflow is not in the conversion. In fact, conversions
of values outside the range of the target type are never
considered as `overflow'. The semantics are quite different.
(1) In the case of converting to an unsigned integer type,
the results are strictly defined to wrap around, as if
the maximum value plus one was added or subtracted
until within the range.
(2) In the case of converting to a signed integer type, the
resulting value is implementation defined, or (in C99)
an implementation-defined signal may be raised. However,
there is not an outright undefined behaviour.
(3) When the result of an unsigned arithmetic operation
doesn't fit within the range, unsigned types never
overflow -- they wrap around.
(4) On the other hand, when computing an arithmetic overflow
in a signed type there is immediate undefined behaviour.
The standard doesn't specify an implementation-defined
result or signal.
In practise, of course, many 2's complement implementations
behave exactly the same for all four cases, which leads to
confusion.
> But probably I've missed something.
If the value returned by strlen is greater than INT_MAX,
the comparison will always be true. Then after some time
while incrementing through the loop, i will equal INT_MAX,
it will be incremented once more, and overflow will occur.
This is arithmetic overflow in a signed type, not a
conversion, and so it is undefined behaviour.
--
Simon.
> Neil Cerutti wrote:
>
> <snip>
> >
> > Here's a slightly less trivial example, that allows me to make my
> > point:
> >
> > void foo(int arg, char *s)
> > {
> > int i; /* wrong */
> > for (i = 0; i < strlen(s); ++i) do_something(s[i]);
> > }
> >
> > Using this example, it becomes possible to say that i ought to be
> > of type size_t, making it's range equal to strlen's range.
>
> And so it should. But don't you think it's better to move the strlen out of
> the loop?
No. If do_something() can set s[i] to '\0', the loop will abort next
time, and this effect may have been intentional. If do_something() never
changes s[i], or rather, never sets it to the null character, the
compiler can figure that out and optimise the strlen() call away itself.
And leaving the strlen() where it is makes for a semantically better
(read: more naturally expressed) program.
Richard
Ahh, I see it's not in the comparison but in the increment.
Since when is allowed INT_MAX to be less than 5? I may have more
information than the compiler, therefore the compiler must trust me.
>You should always use size_t for loop iterators whose bound
>is expressed in size_t. This includes arrays when you use
> sizeof foo / sizeof *foo
>as the bound.
Sheer bullshit! If I *know* that int is enough, there's NO reason for
using size_t.
>> test.c:3: warning: unused parameter `arg'
>>
>> I can see NO good reason for doing something with arg to keep
>> -W silent and I cannot drop it from the function interface
>> (which is externally imposed).
>
>In my experience externally imposed interfaces are uncommon,
Have a look at the specification of signal() sometime.
>and I see the odd cast to void as useful self-documentation.
>It lets the reader of the code immediately see that you
>intentially do not use the value of the argument.
Or he might start wondering why I am doing such a silly thing as casting
an otherwise unused argument to void.
If I don't use the value of the argument (as is usually the case with
my signal handlers), what is the obvious conclusion?
>> Likewise, I don't want to declare i as unsigned for the
>> *sole* reason of shutting up -W (or cast the return value
>> of strlen). I only use unsigned variables when I have a
>> good reason for that, because of reasons discussed in a
>> different thread.
>
>But there is a very good reason to use a size_t variable here!
Nope! Single letter variables are often reused as loop counters and
temporary variables. More often than not, the type int is more
appropriate than an unsigned type and the decision should be mine, not
compiler's, anyway.
>So, I would write:
> #include <string.h>
>
> void foo(int arg)
> {
> (void)arg;
> for (size_t i = 0, n = strlen("abcde"); i < n; i++)
> {
> /* do something */
> }
> }
>for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
>gives no warnings.
That's precisely my point: why bother with options that *force* you to
code around them? What guarantee do you have that *another* compiler
won't complain about the useless statement (void)arg; ?
Apart from that, your code is not portable to *most* C compilers, for no
*good* reason at all.
It's not possible, if do_something is a function. And if do_something
is a macro, it does not have proper notation.
Jirka
I said "potential bug". There is no bug in your code,
but in most cases when looping through a string there
is the possibility of it being of any length, and it
is quite possible it could exceed INT_MAX.
You clearly like to write code that gets the job done but
leaves no room for expansion or re-use. I prefer to code
in the most robust way available.
> >You should always use size_t for loop iterators whose
> >bound is expressed in size_t. This includes arrays
> >when you use
> > sizeof foo / sizeof *foo
> >as the bound.
>
> Sheer bullshit! If I *know* that int is enough, there's
> NO reason for using size_t.
Again, you know that int is enough now, but who knows what
changes you or other people may wish to make to your code
in the future? It is better to do things properly now so
that future expansion will be painless.
> >In my experience externally imposed interfaces are uncommon,
>
> Have a look at the specification of signal() sometime.
Name some common, portable, standard-conforming uses of signal().
> >and I see the odd cast to void as useful self-documentation.
> >It lets the reader of the code immediately see that you
> >intentially do not use the value of the argument.
>
> Or he might start wondering why I am doing such a silly thing
> as casting an otherwise unused argument to void.
The cast to void is a fairly well-known signal for "I don't
care what value this expression has".
> If I don't use the value of the argument (as is usually the
> case with my signal handlers), what is the obvious conclusion?
If the function is long and/or complicated it may not be obvious
at a glance whether or not each argument is actually used.
Furthermore the non-use of an argument is so often a mistake that
a reader is forced to reevaluate whether or not you really did
mean to not use it the argument.
> > But there is a very good reason to use a size_t
> > variable here!
>
> Nope! Single letter variables are often reused as loop
> counters and temporary variables. More often than not,
> the type int is more appropriate than an unsigned type
> and the decision should be mine, not compiler's, anyway.
Variables should be reduced to the minimum scope necessary.
Single letter variables should not be reused, this creates
confusion over whether their value is significant between
uses.
I like the for(type i=0; i<n; i++) form from C99, where the
variable goes out of scope immediately on exit from the loop.
> >So, I would write:
> > #include <string.h>
> >
> > void foo(int arg)
> > {
> > (void)arg;
> > for (size_t i = 0, n = strlen("abcde"); i < n; i++)
> > {
> > /* do something */
> > }
> > }
> >for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
> >gives no warnings.
>
> That's precisely my point: why bother with options that
> *force* you to code around them?
I don't feel forced to code around it! I believe it is good
style to code in such a way that the warnings don't come up.
> What guarantee do you have that *another* compiler
> won't complain about the useless statement (void)arg; ?
None; a compiler is allowed to complain about anything.
However, in my experience compilers universally take a
cast as a sign to shut up.
> Apart from that, your code is not portable to *most* C
> compilers, for no *good* reason at all.
Bogus. My code is portable to *all* C compilers.
Most of the compilers that used to be C compilers,
are now obsolete. C99 replaced C89. C89 is not C.
Come to think of it, since I started programming in C
after C99 was released, I've never used a C compiler!
:-)
--
Simon.
Intel's C compiler does not, so "universally" is too strong.
int i = 42;
char *p = (char *)i;
main.c(155): remark #171: invalid type conversion: "int" to "char *"
char *p = (char *)i;
^
Jirka
> No. If do_something() can set s[i] to '\0', the loop will abort next
> time, and this effect may have been intentional. If do_something() never
> changes s[i], or rather, never sets it to the null character, the
> compiler can figure that out and optimise the strlen() call away itself.
Not knowing much about modern optimizing compilers, and also not wanting
to drag this thread off-topic, but just out of curiosity: How far do
compilers go when looking at such code? Do the optimizations cross
function calls?
> And leaving the strlen() where it is makes for a semantically better
> (read: more naturally expressed) program.
True. But in my mind, strlen() is still nothing but a dumb loop that
counts all non-zero characters from the beginning of a string each time it
is called, so buffering strlen()'s result in some local variable whenever
I want to use a (constant-length) string's length more than once is a
habit of mine that looks pretty unbreakable.
--Daniel
--
"With me is nothing wrong! And with you?" (from r.a.m.p)
> Or he might start wondering why I am doing such a silly thing as casting
> an otherwise unused argument to void.
>
> If I don't use the value of the argument (as is usually the case with
> my signal handlers), what is the obvious conclusion?
That you don't need it. But if you like to compile with all warnings set
to full blast (like I do), it is all too easy to miss the one important
diagnostic in a screenful of "unused argument" warnings. I once wasted
half an afternoon looking for a bug which was indeed caused by an unused
argument, and I only found it by (void)ing the intentionally unused
arguments in two dozen signal handlers.
>>for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
>>gives no warnings.
>
> That's precisely my point: why bother with options that *force* you to
> code around them?
Reason given above.
> What guarantee do you have that *another* compiler
> won't complain about the useless statement (void)arg; ?
None. If I wanted to code in such a way that all compilers happily ate my
code without spitting out warnings, I'd probably have to define a macro
THROWAWAY(arg) which expands to different things for different compilers.
True. But people _do_ use all-lower-caps macros. All the more reason to
leave the strlen() in and trust the optimiser, just to spite that kind
of person <g>.
Ricahrd
> Richard Bos <r...@hoekstra-uitgeverij.nl> wrote
>
> > And leaving the strlen() where it is makes for a semantically better
> > (read: more naturally expressed) program.
>
> True. But in my mind, strlen() is still nothing but a dumb loop that
> counts all non-zero characters from the beginning of a string each time it
> is called,
Ah. And this is where you're wrong. strlen() is a function that return
the length of the string. That it is entirely likely that it does this
by counting characters should not prevent you from thinking on a higher
level. After all, _you're_ not a microprocessor.
Richard
>"Dan Pop" <Dan...@cern.ch> wrote:
>> "Simon Biber" <sbi...@optushome.com.au> writes:
>> > There is very good reason for the warning here as it
>> > has uncovered a potential bug in your code. If the
>> > value returned by strlen is greater than INT_MAX,
>> > your program has undefined behaviour due to overflow.
>>
>> Since when is allowed INT_MAX to be less than 5? I may
>> have more information than the compiler, therefore the
>> compiler must trust me.
>
>I said "potential bug". There is no bug in your code,
>but in most cases when looping through a string there
>is the possibility of it being of any length, and it
>is quite possible it could exceed INT_MAX.
But the point is that I have additional information that rules out this
*theoretical* possibility. Therefore, there is no good reason for using
size_t.
Apart from that, when was the last time you used a string whose size
exceeded INT_MAX, so that the "quite possible" in your assertion is
justified?
>You clearly like to write code that gets the job done but
>leaves no room for expansion or re-use. I prefer to code
>in the most robust way available.
Bullshit. I've never had any problem reusing or expanding my code.
If I decide, at design time, that the right type for a variable is int,
then I know what I'm doing. The compiler has no business to question my
decision.
>> >You should always use size_t for loop iterators whose
>> >bound is expressed in size_t. This includes arrays
>> >when you use
>> > sizeof foo / sizeof *foo
>> >as the bound.
>>
>> Sheer bullshit! If I *know* that int is enough, there's
>> NO reason for using size_t.
>
>Again, you know that int is enough now, but who knows what
>changes you or other people may wish to make to your code
>in the future? It is better to do things properly now so
>that future expansion will be painless.
You're missing the point! Unsigned variables have plenty of pitfalls
and one of them could affect the future changes (especially if they are
done by someone with less experience). By choosing the type int, where
it is the *right* type, I'm ensuring that even a non-experienced
programmer can maintain the code. If you still can't see my point,
replace strlen(something) by sizeof(double) in my original example.
In theory, sizeof(double) could exceed 32767, yet I'm perfectly willing
to ignore this possibility.
>> >In my experience externally imposed interfaces are uncommon,
>>
>> Have a look at the specification of signal() sometime.
>
>Name some common, portable, standard-conforming uses of signal().
#include <signal.h>
volatile sig_atomic_t interrupt;
void handler(int signo)
{
interrupt = 1;
}
...
signal(SIGINT, handler);
signal(SIGTERM, handler);
>> >and I see the odd cast to void as useful self-documentation.
>> >It lets the reader of the code immediately see that you
>> >intentially do not use the value of the argument.
>>
>> Or he might start wondering why I am doing such a silly thing
>> as casting an otherwise unused argument to void.
>
>The cast to void is a fairly well-known signal for "I don't
>care what value this expression has".
Chapter and verse, please. Or other source for this widespread knowledge.
>> If I don't use the value of the argument (as is usually the
>> case with my signal handlers), what is the obvious conclusion?
>
>If the function is long and/or complicated it may not be obvious
>at a glance whether or not each argument is actually used.
Why should anyone care?
>Furthermore the non-use of an argument is so often a mistake that
^^^^^^^^
>a reader is forced to reevaluate whether or not you really did
>mean to not use it the argument.
Care to produce some supporting data for "so often"? I've never ignored
an argument by mistake, each and every time it was a deliberate decision.
>> > But there is a very good reason to use a size_t
>> > variable here!
>>
>> Nope! Single letter variables are often reused as loop
>> counters and temporary variables. More often than not,
>> the type int is more appropriate than an unsigned type
>> and the decision should be mine, not compiler's, anyway.
>
>Variables should be reduced to the minimum scope necessary.
That would mean opening plenty of blocks for no good reason. IIRC, it
was E.R. Tisdale advocating this approach.
>Single letter variables should not be reused, this creates
>confusion over whether their value is significant between
>uses.
No such confusion is possible, when the reuse starts be assigning a new
value. It would be downright idiotic to use a different loop control
variable for each independent loop in a function.
>I like the for(type i=0; i<n; i++) form from C99, where the
>variable goes out of scope immediately on exit from the loop.
It's non-portable. Some people do care about portability, even if you
don't.
>> >So, I would write:
>> > #include <string.h>
>> >
>> > void foo(int arg)
>> > {
>> > (void)arg;
>> > for (size_t i = 0, n = strlen("abcde"); i < n; i++)
>> > {
>> > /* do something */
>> > }
>> > }
>> >for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
>> >gives no warnings.
>>
>> That's precisely my point: why bother with options that
>> *force* you to code around them?
>
>I don't feel forced to code around it! I believe it is good
>style to code in such a way that the warnings don't come up.
I don't. While the unused argument issue is harmless, the gratuitous
usage of unsigned variables is NOT.
>> What guarantee do you have that *another* compiler
>> won't complain about the useless statement (void)arg; ?
>
>None; a compiler is allowed to complain about anything.
>However, in my experience compilers universally take a
>cast as a sign to shut up.
Is it "your experience" or "universally"?
>> Apart from that, your code is not portable to *most* C
>> compilers, for no *good* reason at all.
>
>Bogus. My code is portable to *all* C compilers.
By a bogus definition of C. Your code is non-portable to most of
the real world C compilers, period.
>Most of the compilers that used to be C compilers,
>are now obsolete. C99 replaced C89. C89 is not C.
You're severely confused. One ISO standard replaced another. Up to now,
this had no significant impact either on the industry or on the academia.
The C programming community at large is ignoring the C99 specification.
Furthermore, as attested by comp.std.c, copies of the ISO C90 standard
are still in constant demand (and at least one national standardisation
organisation, BSI, is currently selling them).
The value of an ISO standard is determined by its impact on the industry
that's supposed to use it. Until now, C99 had practically none.
And it came to pass that Dan's cunning rhetorical trap was
sprung.
> I may have more information than the compiler, therefore the
> compiler must trust me.
That makes me wonder, In what typical usages are comparison
between signed and unsigned likely to be wrong? Are those cases
more or less common than Dan's example usage?
If I accidentally compare an unsigned to a negative integer
literal, or any expression the compiler can prove is negative, I
would like to be warned.
--
Neil Cerutti
>If I accidentally compare an unsigned to a negative integer
>literal, or any expression the compiler can prove is negative, I
>would like to be warned.
Me, too.
However, do_something() cannot change s[i]. You may recall that C
passes by value :-) My suggested modification is:
void foo(int arg, char *s)
{
size_t i, lgh;
for (i = 0, lgh = strlen(s); i < lgh; ++i) do_something(s[i]);
}
--
Chuck F (cbfal...@yahoo.com) (cbfal...@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
This is why I said "in my experience". I have never used Intel's
C compiler.
--
Simon.
Yes there is - to avoid type conversions. A type conversion
from size_t to int for each comparison may be inefficient.
> Apart from that, when was the last time you used a string whose
> size exceeded INT_MAX, so that the "quite possible" in your
> assertion is justified?
I regularly read strings from files. I have no control over
what size file my user throws at the program. I prefer not to
impose any restrictions on what size input to accept.
> Bullshit. I've never had any problem reusing or expanding my
> code. If I decide, at design time, that the right type for a
> variable is int, then I know what I'm doing. The compiler has
> no business to question my decision.
If you tell the compiler to warn you of potentially dangerous
practises then it is the compiler's business to question your
decisions. I like my compiler to do so.
> You're missing the point! Unsigned variables have plenty of
> pitfalls and one of them could affect the future changes
> (especially if they are done by someone with less experience).
> By choosing the type int, where it is the *right* type, I'm
> ensuring that even a non-experienced programmer can maintain
> the code.
Please elaborate. What are the pitfalls?
> If you still can't see my point, replace strlen(something)
> by sizeof(double) in my original example. In theory,
> sizeof(double) could exceed 32767, yet I'm perfectly
> willing to ignore this possibility.
I know the possibility is stupidly low, but the principle
remains. When you have the opportunity, why not allow for it?
> #include <signal.h>
>
> volatile sig_atomic_t interrupt;
>
> void handler(int signo)
> {
> interrupt = 1;
> }
> ...
> signal(SIGINT, handler);
> signal(SIGTERM, handler);
And what are the portable semantics of this code? An
implementation need not generate either of these signals,
except as a result of explicit calls to the raise function.
If you are calling raise yourself, why not just set
`interrupt = 1' yourself?
> >The cast to void is a fairly well-known signal for "I don't
> >care what value this expression has".
>
> Chapter and verse, please. Or other source for this widespread
> knowledge.
Chapter and verse: 6.3.2.2 "If an expression of any other type
is evaluated as a void expression, its value or designator is
discarded."
Other source: "Jamshid Afshar" jam...@ut-emx.uucp wrote
in message 82...@ut-emx.uucp "I agree void casts [...] might
even be better style because it makes it obvious to future
maintainers that you are purposely ignoring the return value."
Another source: "Lawrence Kirby" fr...@genesis.demon.co.uk
wrote in message 931391...@genesis.demon.co.uk "Casting
to void: [...] it stresses that the returned value is being
deliberately ignored."
> >If the function is long and/or complicated it may not be obvious
> >at a glance whether or not each argument is actually used.
>
> Why should anyone care?
If someone went to the trouble of passing in an argument to
the function, they generally expect the function to actually
make use of that argument in some way.
> >Furthermore the non-use of an argument is so often a mistake that
> ^^^^^^^^
> >a reader is forced to reevaluate whether or not you really did
> >mean to not use it the argument.
>
> Care to produce some supporting data for "so often"? I've never
> ignored an argument by mistake, each and every time it was a
> deliberate decision.
In the process of redesigning code, I sometimes change the way
parameters are passed around between functions, and sometimes
forget that a function still receives a particular piece of
data although it no longer actually needs it. In that case it
is useful for the compiler to let me know so I can eliminate
this unnecessary argument.
> >Variables should be reduced to the minimum scope necessary.
>
> That would mean opening plenty of blocks for no good reason. IIRC,
> it was E.R. Tisdale advocating this approach.
I thought it was Joona Palaste, or perhaps Emmanuel Delahaye.
Those two I consider to be knowledgeable regulars, somewhat
different to E. Robert Tisdale who sometimes seems trollish.
Anyway, no, I don't go to as large an extreme as to open blocks
for no good reason. What I do is to only apply this rule when
a new block is to be opened anyway, for a control statement.
> >Single letter variables should not be reused, this creates
> >confusion over whether their value is significant between
> >uses.
>
> No such confusion is possible, when the reuse starts be assigning
> a new value. It would be downright idiotic to use a different
> loop control variable for each independent loop in a function.
Why is that?
> >I like the for(type i=0; i<n; i++) form from C99, where the
> >variable goes out of scope immediately on exit from the loop.
>
> It's non-portable. Some people do care about portability, even
> if you don't.
I care about portability in the sense of portable to C99
implementations, all one single implementation, which I
have only tested on their web site. :-)
http://www.comeaucomputing.com/tryitout/
> >I don't feel forced to code around it! I believe it is good
> >style to code in such a way that the warnings don't come up.
>
> I don't. While the unused argument issue is harmless, the
> gratuitous usage of unsigned variables is NOT.
What is harmful about unsigned variables?
> >None; a compiler is allowed to complain about anything.
> >However, in my experience compilers universally take a
> >cast as a sign to shut up.
>
> Is it "your experience" or "universally"?
In my experience, universally. The "in my experience" takes
precedence over the "universally", in standard English grammar.
I have been informed by Jirka Klaue that the Intel C compiler
does still warn about invalid conversions when a cast is
supplied.
> By a bogus definition of C. Your code is non-portable to most
> of the real world C compilers, period.
What real world C compilers? The only C compiler I know of
is Comeau. My code is portable to it. :-)
> You're severely confused. One ISO standard replaced another.
> Up to now, this had no significant impact either on the
> industry or on the academia. The C programming community at
> large is ignoring the C99 specification.
The C course I took at university spent one lecture explaining
the changes made in C99, this was two years ago in 2001.
> Furthermore, as attested by comp.std.c, copies of the ISO C90
> standard are still in constant demand (and at least one national
> standardisation organisation, BSI, is currently selling them).
And I occasionally have cause to look something up in it,
out of historical interest.
> The value of an ISO standard is determined by its impact on
> the industry that's supposed to use it. Until now, C99 had
> practically none.
You should be able to tell I am deliberately taking a
political stance on C99.
--
Simon.
> Richard Bos wrote:
> > No. If do_something() can set s[i] to '\0', the loop will abort
> > next time, and this effect may have been intentional. If
> > do_something() never changes s[i], or rather, never sets it to
> > the null character, the compiler can figure that out and optimise
> > the strlen() call away itself. And leaving the strlen() where it
> > is makes for a semantically better (read: more naturally
> > expressed) program.
>
> However, do_something() cannot change s[i]. You may recall that C
> passes by value :-)
Oh? Ask Jirka <g>. Some people _do_ name their macros in lower case, and
besides, I was assuming that do_something was a placeholder anyway.
> My suggested modification is:
>
> void foo(int arg, char *s)
> {
> size_t i, lgh;
> for (i = 0, lgh = strlen(s); i < lgh; ++i) do_something(s[i]);
> }
Yes, but _why_? Surely optimisers can be trusted a bit better these
days?
Richard
>"Dan Pop" <Dan...@cern.ch> wrote:
>> But the point is that I have additional information that rules
>> out this *theoretical* possibility. Therefore, there is no good
>> reason for using size_t.
>
>Yes there is - to avoid type conversions. A type conversion
>from size_t to int for each comparison may be inefficient.
Don't be idiot! The example provided was purely schematic. The idea is
that i is used in the loop for other purposes, including mixed type
expressions, therefore conversions are unavoidable. And my usage causes
minimal surprise in such expressions (in case i is going to be used
together with negative int's).
>> Apart from that, when was the last time you used a string whose
>> size exceeded INT_MAX, so that the "quite possible" in your
>> assertion is justified?
>
>I regularly read strings from files. I have no control over
>what size file my user throws at the program. I prefer not to
>impose any restrictions on what size input to accept.
I do. If the size of a line of text is unreasonable, the user is feeding
garbage to my program and there is no point in processing it as if it were
valid data. Much better to tell the user that he is doing something
wrong. And, in my book, a line of text longer than 32k is not reasonable
user input.
>> Bullshit. I've never had any problem reusing or expanding my
>> code. If I decide, at design time, that the right type for a
>> variable is int, then I know what I'm doing. The compiler has
>> no business to question my decision.
>
>If you tell the compiler to warn you of potentially dangerous
>practises then it is the compiler's business to question your
>decisions. I like my compiler to do so.
In C, practically everything is potentially dangerous. Would you like
the compiler to warn you that i + j may overflow or wrap around, that
*any* strcpy call can overflow the input buffer and so on? There is NO
point in *arbitrarily* singling out certain features.
>> You're missing the point! Unsigned variables have plenty of
>> pitfalls and one of them could affect the future changes
>> (especially if they are done by someone with less experience).
>> By choosing the type int, where it is the *right* type, I'm
>> ensuring that even a non-experienced programmer can maintain
>> the code.
>
>Please elaborate. What are the pitfalls?
Time to learn C, if you can't figure them out.
>> If you still can't see my point, replace strlen(something)
>> by sizeof(double) in my original example. In theory,
>> sizeof(double) could exceed 32767, yet I'm perfectly
>> willing to ignore this possibility.
>
>I know the possibility is stupidly low, but the principle
>remains. When you have the opportunity, why not allow for it?
Because of the much bigger potential for bugs of your advocated approach.
I prefer to choose the safer way.
>> #include <signal.h>
>>
>> volatile sig_atomic_t interrupt;
>>
>> void handler(int signo)
>> {
>> interrupt = 1;
>> }
>> ...
>> signal(SIGINT, handler);
>> signal(SIGTERM, handler);
>
>And what are the portable semantics of this code? An
>implementation need not generate either of these signals,
>except as a result of explicit calls to the raise function.
>If you are calling raise yourself, why not just set
>`interrupt = 1' yourself?
Obvious answer: if the implementation *does* raise them, the program can
react to them. If it doesn't, the code is still perfectly harmless and
portable. How about engaging your brain before asking idiotic questions?
>> >The cast to void is a fairly well-known signal for "I don't
>> >care what value this expression has".
>>
>> Chapter and verse, please. Or other source for this widespread
>> knowledge.
>
>Chapter and verse: 6.3.2.2 "If an expression of any other type
>is evaluated as a void expression, its value or designator is
>discarded."
An excellent reason for a compiler to complain about useless code.
>Other source: "Jamshid Afshar" jam...@ut-emx.uucp wrote
>in message 82...@ut-emx.uucp "I agree void casts [...] might
>even be better style because it makes it obvious to future
>maintainers that you are purposely ignoring the return value."
>
>Another source: "Lawrence Kirby" fr...@genesis.demon.co.uk
>wrote in message 931391...@genesis.demon.co.uk "Casting
>to void: [...] it stresses that the returned value is being
>deliberately ignored."
I wasn't asking about opinions of randomly selected people. Neither
Jamshid Afshar nor Lawrence Kirby have authored C books in widespread
usage among beginners.
>> >If the function is long and/or complicated it may not be obvious
>> >at a glance whether or not each argument is actually used.
>>
>> Why should anyone care?
>
>If someone went to the trouble of passing in an argument to
>the function, they generally expect the function to actually
>make use of that argument in some way.
You missed the point: if the function is long and/or complicated, the
human reader is not likely to even notice that an argument is not used.
If he does, the most sensible conclusion is that, once upon a time, the
argument was needed, but it is no longer the case.
>> >Furthermore the non-use of an argument is so often a mistake that
>> ^^^^^^^^
>> >a reader is forced to reevaluate whether or not you really did
>> >mean to not use it the argument.
>>
>> Care to produce some supporting data for "so often"? I've never
>> ignored an argument by mistake, each and every time it was a
>> deliberate decision.
>
>In the process of redesigning code, I sometimes change the way
>parameters are passed around between functions, and sometimes
>forget that a function still receives a particular piece of
>data although it no longer actually needs it. In that case it
>is useful for the compiler to let me know so I can eliminate
>this unnecessary argument.
If you need to redesign the code, it means that you didn't design it
properly in the first place. I don't need to redesign my code, even if
the program specification changes.
>> >Variables should be reduced to the minimum scope necessary.
>>
>> That would mean opening plenty of blocks for no good reason. IIRC,
>> it was E.R. Tisdale advocating this approach.
>
>I thought it was Joona Palaste, or perhaps Emmanuel Delahaye.
I don't.
>Those two I consider to be knowledgeable regulars, somewhat
>different to E. Robert Tisdale who sometimes seems trollish.
>
>Anyway, no, I don't go to as large an extreme as to open blocks
>for no good reason. What I do is to only apply this rule when
>a new block is to be opened anyway, for a control statement.
Unfortunately, the loop control variable (which is what we're talking
about), has to be declared *before* the block is opened. At least, this
is the case of the commonly implemented C (as opposed to your pipe dream
C definition).
>> >Single letter variables should not be reused, this creates
>> >confusion over whether their value is significant between
>> >uses.
>>
>> No such confusion is possible, when the reuse starts be assigning
>> a new value. It would be downright idiotic to use a different
>> loop control variable for each independent loop in a function.
>
>Why is that?
Because there is NO good reason for variable proliferation. Why declare
10 variables for a job that can be perfectly done with one?
>> >I like the for(type i=0; i<n; i++) form from C99, where the
>> >variable goes out of scope immediately on exit from the loop.
>>
>> It's non-portable. Some people do care about portability, even
>> if you don't.
>
>I care about portability in the sense of portable to C99
>implementations, all one single implementation, which I
>have only tested on their web site. :-)
> http://www.comeaucomputing.com/tryitout/
Portable to one implementation is a perfect example of oxymoron.
>> >I don't feel forced to code around it! I believe it is good
>> >style to code in such a way that the warnings don't come up.
>>
>> I don't. While the unused argument issue is harmless, the
>> gratuitous usage of unsigned variables is NOT.
>
>What is harmful about unsigned variables?
Nothing, until they get mixed with signed variables.
>> >None; a compiler is allowed to complain about anything.
>> >However, in my experience compilers universally take a
>> >cast as a sign to shut up.
>>
>> Is it "your experience" or "universally"?
>
>In my experience, universally. The "in my experience" takes
>precedence over the "universally", in standard English grammar.
If your experience happens to be limited to one compiler, the
"universally" is still bogus, regardless of the standard English grammar.
>> By a bogus definition of C. Your code is non-portable to most
>> of the real world C compilers, period.
>
>What real world C compilers? The only C compiler I know of
>is Comeau. My code is portable to it. :-)
That's because of your bogus definition of C :-)
>> You're severely confused. One ISO standard replaced another.
>> Up to now, this had no significant impact either on the
>> industry or on the academia. The C programming community at
>> large is ignoring the C99 specification.
>
>The C course I took at university spent one lecture explaining
>the changes made in C99, this was two years ago in 2001.
Was this enough to give you an *accurate* picture about C99?
Why didn't they teach C99 during the whole course?
>> Furthermore, as attested by comp.std.c, copies of the ISO C90
>> standard are still in constant demand (and at least one national
>> standardisation organisation, BSI, is currently selling them).
>
>And I occasionally have cause to look something up in it,
>out of historical interest.
Professional programmers have more than a historical interest in it.
>> The value of an ISO standard is determined by its impact on
>> the industry that's supposed to use it. Until now, C99 had
>> practically none.
>
>You should be able to tell I am deliberately taking a
>political stance on C99.
But this is a *technical* newsgroup, so please take your political stances
somewhere else.