sscanf behaviour change


I was migrating an instrumental function from Igor 6 (x86) to Igor 8 (x64).

The driver works and I could toggle the device on/off, but some setting can no longer be changed. As it turns out, it seem the sscanf function does not work the same way, kindly correct me if I am wrong.

For example, with the below code

function test()
	string ctrlName = "SGS1ExtRef"

	variable SGSIndex	//S:I used index for a numerical representation, not to be confused with SGSNum which is a string.
	sscanf ctrlName, "SGS %f", SGSIndex
	print SGSIndex

The output of Igor 8.00 gives 0 (wrong)
The output of Igor 6.37 gives 1 (desired)

Maybe I can try another similar function?
It would still be great if sscanf can work again so I don't have to change all the functions related.

I also tried to use the NumberByKey function:

SGSIndex = NumberByKey("SGS", ctrlName)

It somehow returned Nan.

I tested your function in various versions of Igor:

Igor6 Mac: 1
Igor6 Win: 1
Igor7 Mac: 1
Igor7 Win: 1
Igor8 Mac: 1
Igor8 Win: 0

Igor8 on Windows is the outlier. I suspect that this is caused by a change in the Microsoft library that provides sscanf.

I get the same results for "SGS %f" and "SGS%f" (no space).

I will investigate.

Here is a workaround: (Update: This workaround doesn not work in Igor8 on Windows - details to follow.)

Function Test()
    String ctrlName = "SGS1ExtRef"
    String temp = ctrlName[3,strlen(ctrlName)-1]
    Variable SGSIndex
    sscanf temp, "%f", SGSIndex
    Print SGSIndex



The problem is a subtle change in sscanf between Visual C++ 2013 (used for Igor7) and Visual C++ 2015 (used for Igor8). This function illustrates:

Function Demo()
    Variable value
    String format = "%f"
    String text
    text = "1E"
    sscanf text, format, value
    Printf "text=\"%s\", format=\"%s\", V_Flag=%d, value=%g\r", text, format, V_Flag, value
    text = "1X"
    sscanf text, format, value
    Printf "text=\"%s\", format=\"%s\", V_Flag=%d, value=%g\r", text, format, V_Flag, value

sscanf is trying to find a valid number in "text" to match "%f".

sscanf in VC2013 accepts "1E" as a valid number.

sscanf in VC2015 rejects "1E" as a valid number but accepts "1E0". There is, unfortunately, nothing practical that we can do about this subtle change.

A workaround is to change %f to %d in your original function. Then sscanf in VC2015 will be happy to accept "1" as an integer and will not be put off by the "E" following the "1".



I think the change in sscanf behaviour is actually fixing a bug. I found where the reporter states a similiar problem in glibc which reamains unsolved.

Compiling the following test program with gcc 6.3 and clang 6.0

#include <stdio.h>

int main(int argc, char** argv)
  char str1[] = "test 1.5E0";
  char str2[] = "test 1.5E";
  float num = 0;

  int ret = sscanf(str1, "test %f", &num);
  printf("ret %d, num %f\n", ret, num);

  ret = sscanf(str2, "test %f", &num);
  printf("ret %d, num %f\n", ret, num);
  return 0;

gives for clang

ret 1, num 1.500000
ret -1, num 0.000000

and for gcc

ret 1, num 1.500000
ret 1, num 1.500000

So also the FLOSS compilers don't agree here.

The official microsoft documentation says for %f:

Floating-point value consisting of optional sign (+ or -), series of one
or more decimal digits containing decimal point, and optional exponent
("e" or "E") followed by an optionally signed integer value.

where at least I had to read it twice to notice that the last optionally refers to the sign and not to the integer value.