Journal Articles

CVu Journal Vol 12, #2 - Mar 2000 + Programming Topics
Browse in : All > Journals > CVu > 122 (18)
All > Topics > Programming (877)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: Questions and Answers

Author: Administrator

Date: 05 March 2000 13:15:35 +00:00 or Sun, 05 March 2000 13:15:35 +00:00

Summary: 

Body: 

First a letter about something I wrote about the undefined behaviour in printf("%d %d", fn(i++), fn(i++))

Hi Francis,

Actually you missed one. A few years ago when I was "doing" the "when does the ++ actually happen" thing, I was experimenting with Borland C++ v3 or 4, can't remember which, and I was using the expression i++ + i++ + i++ + i++ + i++, with i initialised to 1 this produced an output of 5 and i was left at 10. Drilling down to the machine code level I found that the ++es were being left until "after" the ';', so effectively I had printf("%d",i+i+i+i+i); ++ ++ ++ ++ ++. If this is still true for Borland 5, you should find that printf("%d %d", fn(i++), fn(i++)) with i initialised to zero will call fn with the value zero both times resulting in the output '1 1'. THEN, i will be ++'ed twice, and will be left with the value 2.

Dave Spence

I do not think I missed anything other than failing to present one more way in which the user can get unexpected results. Borland are entitled to defend themselves on the basis that the code has undefined behaviour. The existence of sequence points at entry and exit to a function is irrelevant because the evaluation of i++ in each case is external to the function. The function needs the value but does not have access to the storage. It might be slightly different in the case of C++ references. Francis

Answers

Now to a few answers

Trap - Answer from Nigel Eke

In the last issue I published a short problem in my Bits & Pieces column (as a filler) which could just as well have gone into the Q&A column. Being a little short of responses for this column I have reclassified the following response.

The possible trap that can be fallen into with the Fused class becomes clear if the lifetime of a Fused object and the lifetime of the referenced integer are considered. If the lifetime of the object is longer than the lifetime of the referenced integer then you just need to ask yourself the question "What is being referred to if the object uses the member variable icr after the original referenced integer no longer exists?"

Falling into the trap-for the purposes of this demo I made icr public:

#include <iostream>
class Fused {
public:
  int const& icr;
  Fused (int const& iref) : icr(iref) {}
};
Fused* foo (){
  int const anInteger = 4;
  return new Fused (anInteger);
}
void bar (){
  char a[] = "Mary had a little lamb";
  cout << a;
}
int main(int argc, char **argv){
  Fused* pFused (foo ());
// "anInteger" no longer exists,
// so neither does "pFused->icr"
  bar (); 
// Use the stack area where icr& is located...
  cout << pFused->icr << endl;
  delete pFused;
  return 0;
}

I think the above will probably demonstrate the problem in most environments - it certainly does with Windows NT3 / Borland C++ Builder 3.

Editor: Nigel has spotted the essence of the problem. The vicious twist is that because of the use of a const & it will even bind the class reference to a temporary so the following declaration will, I think, compile:

int main(){
  Fused fuse(4);
  cout << fuse.icr;
}

Answer to question 1 from Fred Johnson

Problem with odd length data packets.

I am afraid the answer to the above problem is not as simple as it would first appear. Firstly, the reasons for byte orientated software. This is due to two factors.

  1. Early microcomputers were built around 8-bit systems and it was convenient for the manufacturers to produce an 8-bit uart for conversion from parallel to serial mode.

  2. Encoding systems for data (e.g. ASCII) commonly used 7 or 8 bits to represent a character in serial transmission. Since these systems are now regarded as 'standard', any move to change them without overwhelming need will be almost impossible to achieve.

There are two ways in which your requirements may be satisfied

  1. Build your own (very non-standard) uart and serial card. A very expensive and time consuming, non-trivial process.

  2. Make use of current 8-bit technology and send the data in two bytes.

At this point, you can either pad out the bit count to 16 with zero's or alternatively, if your application is safety critical, use the remaining bits in an error correction system.

As for references, the only one I have seen is one chapter of the book The C Toolbox by William James Hunt, published in 1989 by Addison-Wesley, This is now very old and outdated, and also confines itself to IBM PC systems only. You do not say what platform you are working on.

The author does quote another source, C Programmers Guide to Serial Communications by Joe Campbell, but I have not personally seen this book.

Answer to Question 4 (converting to all uppercase )

from R.L. Thornburrow

Converting a string to uppercase is simply a matter of iterating through the string and copying it character by character changing all lowercase letters to uppercase. The best way of achieving this is by using the function toupper() that forms part of the standard C library (which is also accessible through C++). Using toupper (as with tolower which performs the reverse action) is very useful as the case of any lowercase letters including any accented or locale specific characters are changed. Characters already in the desired case, symbols, numbers and the like remain the same. toupper can also determine which character code system is being used (for example ASCII code 65 is A) enabling it to work with other code systems. This increases the portability of the code as system specific issues such as this are resolved by the libraries.

The code below will solve the problem.

string upper_case(string const & s) {
  string::const_iterator p = s.begin();
  string s1 = "";
  while (p != s.end()) {
    s1 += toupper(*p);
    ++p;
  }
  return s1;
}

As the original string is being passed as a const to prevent it from being modfied by the function, the string iterator also has to be declared as a const, hence the use of const_iterator.

New Questions

Question 1: Clipping Trailing Zeros

I am trying to output a double to a string using sprintf. The code I am using right now is

sprintf(buf, "%f ",d); 

where d is a value of type double. What this does is automatically output to six decimal places. So if d = 1.0 buf becomes '1.000000.' A more relevant example would be d = 3.142 resulting in generating '3.142000' in buf Is it possible to clip all the trailing zeroes from the output of a double?

Question 2: Pointer problem

Why doesn't the following change the pointer it is passed?

void findspace(int * points_at, char * text){
  int i;
  for(i=0; i<strlen(text); i++)
    if(text[i] = ' ') points_at = text+i;
  return
}

Question 3: What id Koenig Lookup and what use is it

Can someone explain what on Earth Koenig lookup is. I used to think I understood how overloading worked in C++ but this seems to be no longer true.

Notes: 

More fields may be available via dynamicdata ..