User avatar
Paeryn
Posts: 2734
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Errors in An Introduction to C & GUI Programming.

Wed Apr 17, 2019 4:42 pm

After having a quick look at the new book "An Introduction to C and GUI Programming" there are a couple of errors in the first chapter.

The first is that on page 11 it states that main() has a return type of void. No it doesn't, it has a return type of int.

Worse, on page 18 it states
There are also modifiers which can be applied to variable types. Both char and int can
be used to store both positive and negative numbers, but by applying the unsigned modifier
when one is declared, they can be restricted to only store positive values. So…

char a;
…declares a variable which can hold values from -128 to 127, while…

unsigned char a;
…declares a variable which can hold values from 0 to 255
char is not defined as being a signed type, it is deliberately non-specific as to whether it is signed or unsigned. On ARM systems like the RPi char defaults to behaving as unsigned type. I've seen this type of error numerous times where a char variable is compared to a negative value, on x86 it works but on ARM it will always be false.
She who travels light — forgot something.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 24115
Joined: Sat Jul 30, 2011 7:41 pm

Re: Errors in An Introduction to C & GUI Programming.

Wed Apr 17, 2019 9:35 pm

We are going to laugh our bits off in the office when Simon gets back. The return value from main is a long running saga.

Suffice to say, this is not a technical reference, it's a guide for beginners. Not for those of a more pedantic persuasion.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed. Here's an example...
“I think it’s wrong that only one company makes the game Monopoly.” – Steven Wright

gkaiseril
Posts: 654
Joined: Mon Aug 08, 2016 9:27 pm
Location: Chicago, IL

Re: Errors in An Introduction to C & GUI Programming.

Wed Apr 17, 2019 9:51 pm

The code as provided compiles without error and even runs without reporting an error.
f u cn rd ths, u cn gt a gd jb n cmptr prgrmmng.

jahboater
Posts: 4823
Joined: Wed Feb 04, 2015 6:38 pm

Re: Errors in An Introduction to C & GUI Programming.

Wed Apr 17, 2019 10:03 pm

gkaiseril wrote:
Wed Apr 17, 2019 9:51 pm
The code as provided compiles without error and even runs without reporting an error.
It fails with GCC 8.3 ...

Code: Select all

$ gcc -Wall hello.c -o hello
hello.c:5:1: warning: return type of 'main' is not 'int' [-Wmain]
 main( void )
 ^~~~
$ ./hello
hello world
$ echo $?
12
$ 
it is returning a random value to the shell :(

Its supposed to return zero if the final return from main is omitted.

The code calling main() in the C runtime startup should be something like this:

exit( main( ... ) );

User avatar
Paeryn
Posts: 2734
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 2:18 am

jamesh wrote:
Wed Apr 17, 2019 9:35 pm
We are going to laugh our bits off in the office when Simon gets back. The return value from main is a long running saga.

Suffice to say, this is not a technical reference, it's a guide for beginners. Not for those of a more pedantic persuasion.
I realise that it's not a technical reference and the return type of main() is less of an issue but I've seen plenty of programs written that assume char is signed like it is on x86 which fail the moment it's compiled for ARM (and not always at an immediately obvious point).

Since the RPi is ARM based I'm surprised that the book says that an unqualified char can have a negative value when on that platform it can't. Is the book not targeted with the RPi user in mind?

These aren't complex things, it's no harder to give the correct information from the get go. The hardest thing is to say if you want to guarantee a char can have a range -128 to 127 then use signed char, if you want a guaranteed range of 0 to 255 then use unsigned char. If you only care about having a range of 0 to 127 then you can use char unqualified (or know that the software will only ever be compiled on a certain platform)

I don't expect following details on the ins and outs of archane practices but these two are as basic as it gets. They are there in the standard and has been since since day 1. I see no excuse for it.

We should be teaching the new programmers the correct stuff from day one lest they go on to write some huge important software that fails when transferred onto a new system.
She who travels light — forgot something.

User avatar
PeterO
Posts: 5127
Joined: Sun Jul 22, 2012 4:14 pm

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 6:49 am

Far bigger issue for me is odd decision to cover on GTK2 rather than GTK3 ! GTK3 has been stable (at 3.22) for nearly three years now, so any arguments about GTK3 API stability and backwards compatibility between releases are bogus. :roll:

I thought I was late making the jump from GTK2 to GTK3 two years ago :shock: but this book just looks out of date now :o

If Simon needs help with "letting go" from GTK2 I can help :-)

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
PeterO
Posts: 5127
Joined: Sun Jul 22, 2012 4:14 pm

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 8:05 am

jamesh wrote:
Wed Apr 17, 2019 9:35 pm
We are going to laugh our bits off in the office when Simon gets back. The return value from main is a long running saga.

Suffice to say, this is not a technical reference, it's a guide for beginners. Not for those of a more pedantic persuasion.
Are you saying that "style comes before accuracy" ? That's not a good plan for a book on programming where accuracy is paramount !

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

jahboater
Posts: 4823
Joined: Wed Feb 04, 2015 6:38 pm

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 8:18 am

Paeryn wrote:
Thu Apr 18, 2019 2:18 am
These aren't complex things, it's no harder to give the correct information from the get go. The hardest thing is to say if you want to guarantee a char can have a range -128 to 127 then use signed char, if you want a guaranteed range of 0 to 255 then use unsigned char. If you only care about having a range of 0 to 127 then you can use char unqualified (or know that the software will only ever be compiled on a certain platform)
Thats right, but it isn't always as simple as that :( They are three distinct types. The standard library functions expect unadorned "char". So "signed char" and "unsigned char" are incompatible. Furthermore if you do: unsigned char str = "hello, world"; It will fail on both x86 and ARM.
The only safe option is the compiler flag (which all compilers have AFAIK) for just this reason. -funsigned-char makes x86 chars behave the same as ARM ones. I prefer unsigned as you don't get any unexpected sign-extension when characters are accessed, and its much easier for ARM to deal with.

Code: Select all

#include <stdio.h>

int
main( void )
{
  const unsigned char *str = "hello world";
  puts(str);
}
produces these two warnings on both x86 and ARM:

Code: Select all

hello.c: In function 'main':
hello.c:7:30: warning: pointer targets in initialization of 'const unsigned char *' from 'char *' differ in signedness [-Wpointer-sign]
   const unsigned char *str = "hello world";
                              ^~~~~~~~~~~~~
hello.c:8:8: warning: pointer targets in passing argument 1 of 'puts' differ in signedness [-Wpointer-sign]
   puts(str);
        ^~~
In file included from hello.c:2:
/usr/include/stdio.h:697:12: note: expected 'const char *' but argument is of type 'const unsigned char *'
 extern int puts (const char *__s);
            ^~~~
As for main()'s signature, it is only necessary to change "void main( void )" to "int main( void )" - there is no need to actually return anything! A simple change which shouldn't upset beginners.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 24115
Joined: Sat Jul 30, 2011 7:41 pm

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 5:54 pm

jahboater wrote:
Thu Apr 18, 2019 8:18 am
Paeryn wrote:
Thu Apr 18, 2019 2:18 am
These aren't complex things, it's no harder to give the correct information from the get go. The hardest thing is to say if you want to guarantee a char can have a range -128 to 127 then use signed char, if you want a guaranteed range of 0 to 255 then use unsigned char. If you only care about having a range of 0 to 127 then you can use char unqualified (or know that the software will only ever be compiled on a certain platform)
Thats right, but it isn't always as simple as that :( They are three distinct types. The standard library functions expect unadorned "char". So "signed char" and "unsigned char" are incompatible. Furthermore if you do: unsigned char str = "hello, world"; It will fail on both x86 and ARM.
The only safe option is the compiler flag (which all compilers have AFAIK) for just this reason. -funsigned-char makes x86 chars behave the same as ARM ones. I prefer unsigned as you don't get any unexpected sign-extension when characters are accessed, and its much easier for ARM to deal with.

Code: Select all

#include <stdio.h>

int
main( void )
{
  const unsigned char *str = "hello world";
  puts(str);
}
produces these two warnings on both x86 and ARM:

Code: Select all

hello.c: In function 'main':
hello.c:7:30: warning: pointer targets in initialization of 'const unsigned char *' from 'char *' differ in signedness [-Wpointer-sign]
   const unsigned char *str = "hello world";
                              ^~~~~~~~~~~~~
hello.c:8:8: warning: pointer targets in passing argument 1 of 'puts' differ in signedness [-Wpointer-sign]
   puts(str);
        ^~~
In file included from hello.c:2:
/usr/include/stdio.h:697:12: note: expected 'const char *' but argument is of type 'const unsigned char *'
 extern int puts (const char *__s);
            ^~~~
As for main()'s signature, it is only necessary to change "void main( void )" to "int main( void )" - there is no need to actually return anything! A simple change which shouldn't upset beginners.
Begineers were already not upset. That's the point.

A bit about C I detest

`unsigned x;`

Perfectly valid C, and perfectly understandable by people who know the specific rule. But bad style.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed. Here's an example...
“I think it’s wrong that only one company makes the game Monopoly.” – Steven Wright

jahboater
Posts: 4823
Joined: Wed Feb 04, 2015 6:38 pm

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 6:19 pm

jamesh wrote:
Thu Apr 18, 2019 5:54 pm
`unsigned x;`

Perfectly valid C, and perfectly understandable by people who know the specific rule. But bad style.
auto x;

still works - which is even worse!
of course C++ has hijacked the auto keyword to mean something completely different ...

User avatar
Paeryn
Posts: 2734
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Errors in An Introduction to C & GUI Programming.

Thu Apr 18, 2019 11:58 pm

My biggest gripe with C is macros, part of the language which can modify your source code before it gets compiled. Though at least nowadays gcc gives fairly decent warnings when it sees potential problems with the changes that they make.
She who travels light — forgot something.

jahboater
Posts: 4823
Joined: Wed Feb 04, 2015 6:38 pm

Re: Errors in An Introduction to C & GUI Programming.

Sat Apr 20, 2019 4:03 pm

Paeryn wrote:
Thu Apr 18, 2019 11:58 pm
My biggest gripe with C is macros, part of the language which can modify your source code before it gets compiled. Though at least nowadays gcc gives fairly decent warnings when it sees potential problems with the changes that they make.
Also their usage is declining I think.
enum's replace many #defines for simple integer numbers, even better if there are a group of related ones.

inline functions replace function like macros with better and safer semantics.

It still seems an overkill to replace something really simple like:-

#define integer(x) (trunc(x) == x)

with a function, but it would likely produce identical code.

User avatar
Paeryn
Posts: 2734
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Errors in An Introduction to C & GUI Programming.

Sat Apr 20, 2019 8:50 pm

jahboater wrote:
Sat Apr 20, 2019 4:03 pm
Paeryn wrote:
Thu Apr 18, 2019 11:58 pm
My biggest gripe with C is macros, part of the language which can modify your source code before it gets compiled. Though at least nowadays gcc gives fairly decent warnings when it sees potential problems with the changes that they make.
Also their usage is declining I think.
enum's replace many #defines for simple integer numbers, even better if there are a group of related ones.

inline functions replace function like macros with better and safer semantics.

It still seems an overkill to replace something really simple like:-

#define integer(x) (trunc(x) == x)

with a function, but it would likely produce identical code.
Not necessarily, x would be evaluated twice so if x has a side effect or multiple return values... E.g. something along the lines of these would likely not give you the result you were hoping for,

Code: Select all

#define integer(x)   (trunc(x) == x)

double ReadNumber(FILE *stream) {
  double value;
  fscanf(stream, "%f", &value);
  return value;
}

void errornous_function(FILE *stream) {
  if (integer(ReadNumber(stream))) {
    printf("Hmm.\n");
  }
  else {
    printf("Oops.\n");
  }
  
  if (integer(rand()) {
    printf("You would think this is always true since rand() returns an int\n");
  }
  else {
    printf("Chances are you'll get false, as you need two consecutive rand() numbers to be identical.\n");
  }
}
The first use integer() has now read two numbers and compared the integer of the first to the double of the second, the second integer() has compared two random integers for equality.
She who travels light — forgot something.

jahboater
Posts: 4823
Joined: Wed Feb 04, 2015 6:38 pm

Re: Errors in An Introduction to C & GUI Programming.

Sun Apr 21, 2019 6:56 am

Sorry, yes, bad choice of example!

Code: Select all

static bool
integer( const double x )
{
  return trunc(x) == x;
}
is much safer and produces the same code.

The only slight problem is that you cant check the function versions with static_assert().

Return to “The MagPi”