Results 1 to 3 of 3

Thread: locale messes up sprintf, but only in Qt program

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jul 2017
    Posts
    37
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default locale messes up sprintf, but only in Qt program

    I have the following function:
    Qt Code:
    1. string ldecimal(double x,double toler)
    2. {
    3. double x2;
    4. int h,i,iexp,chexp;
    5. size_t zpos;
    6. char *dotpos,*epos,*pLcNumeric;
    7. string ret,s,m,antissa,exponent,saveLcNumeric;
    8. char buffer[32],fmt[8];
    9. assert(toler>=0);
    10. pLcNumeric=getenv("LC_NUMERIC");
    11. if (pLcNumeric)
    12. saveLcNumeric=pLcNumeric;
    13. setenv("LC_NUMERIC","C",true);
    14. if (toler>0 && x!=0)
    15. {
    16. iexp=floor(log10(fabs(x/toler))-1);
    17. if (iexp<0)
    18. iexp=0;
    19. }
    20. else
    21. iexp=DBL_DIG-1;
    22. h=-1;
    23. i=iexp;
    24. while (true)
    25. {
    26. sprintf(fmt,"%%.%de",i);
    27. sprintf(buffer,fmt,x);
    28. x2=atof(buffer);
    29. if (h>0 && (fabs(x-x2)<=toler || i>=DBL_DIG+3))
    30. break;
    31. if (fabs(x-x2)>toler || i<=0)
    32. h=1;
    33. i+=h;
    34. }
    35. dotpos=strchr(buffer,'.');
    36. epos=strchr(buffer,'e');
    37. if (epos && !dotpos) // e.g. 2e+00 becomes 2.e+00
    38. {
    39. memmove(epos+1,epos,buffer+31-epos);
    40. dotpos=epos++;
    41. *dotpos=='.';
    42. }
    43. if (dotpos && epos)
    44. {
    45. m=string(buffer,dotpos-buffer);
    46. antissa=string(dotpos+1,epos-dotpos-1);
    47. exponent=string(epos+1);
    48. if (m.length()>1)
    49. {
    50. s=m.substr(0,1);
    51. m.erase(0,1);
    52. }
    53. iexp=atoi(exponent.c_str());
    54. zpos=antissa.find_last_not_of('0');
    55. antissa.erase(zpos+1);
    56. iexp=stoi(exponent);
    57. if (iexp<0 && iexp>-5)
    58. {
    59. antissa=m+antissa;
    60. m="";
    61. iexp++;
    62. }
    63. if (iexp>0)
    64. {
    65. chexp=iexp;
    66. if (chexp>antissa.length())
    67. chexp=antissa.length();
    68. m+=antissa.substr(0,chexp);
    69. antissa.erase(0,chexp);
    70. iexp-=chexp;
    71. }
    72. while (iexp>-5 && iexp<0 && m.length()==0)
    73. {
    74. antissa="0"+antissa;
    75. iexp++;
    76. }
    77. while (iexp<3 && iexp>0 && antissa.length()==0)
    78. {
    79. m+='0';
    80. iexp--;
    81. }
    82. sprintf(buffer,"%d",iexp);
    83. exponent=buffer;
    84. ret=s+m;
    85. if (antissa.length())
    86. ret+='.'+antissa;
    87. if (iexp)
    88. ret+='e'+exponent;
    89. }
    90. else
    91. ret=buffer;
    92. setenv("LC_NUMERIC",saveLcNumeric.c_str(),true);
    93. return ret;
    94. }
    To copy to clipboard, switch view to plain text mode 
    The function is used to format numbers when writing to files, so it has to use '.' for the decimal point regardless of locale. I added the saving and restoring LC_NUMERIC code to fix this bug. It didn't work.

    I am using it in at least two programs: bezitest, which is a non-Qt test program, and viewtin, which is a Qt GUI program. Until I implement hit-testing, viewtin is displaying the coordinates of the cursor in world space. "bezitest ldecimal" outputs, among others, "3.141592653589793". viewtin displays a tooltip saying something like "3,141592653589793,2,718281828459045". I ran it in gdb and found that the comma is put there by sprintf.

    locale outputs the following:
    Qt Code:
    1. LANG=en_DK.UTF-8
    2. LANGUAGE=en_US:es
    3. LC_CTYPE="en_DK.UTF-8"
    4. LC_NUMERIC="en_DK.UTF-8"
    5. LC_TIME="en_DK.UTF-8"
    6. LC_COLLATE="en_DK.UTF-8"
    7. LC_MONETARY="en_DK.UTF-8"
    8. LC_MESSAGES="en_DK.UTF-8"
    9. LC_PAPER="en_DK.UTF-8"
    10. LC_NAME="en_DK.UTF-8"
    11. LC_ADDRESS="en_DK.UTF-8"
    12. LC_TELEPHONE="en_DK.UTF-8"
    13. LC_MEASUREMENT="en_DK.UTF-8"
    14. LC_IDENTIFICATION="en_DK.UTF-8"
    15. LC_ALL=
    To copy to clipboard, switch view to plain text mode 
    LC_NUMERIC is actually unset.

  2. #2
    Join Date
    Jul 2017
    Posts
    37
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: locale messes up sprintf, but only in Qt program

    I catted /proc/<pid>/environ into two files while the programs were running and compared them. They are identical, except for the last entry, which is the name of the program. Here it is, with some entries snipped:
    Qt Code:
    1. XDG_VTNR=7
    2. XDG_SESSION_ID=2
    3. SSH_AGENT_PID=3140
    4. PAM_KWALLET5_LOGIN=<snip>
    5. KDE_MULTIHEAD=false
    6. GPG_AGENT_INFO=/home/phma/.gnupg/S.gpg-agent:0:1
    7. TERM=xterm
    8. SHELL=/bin/bash
    9. XDG_SESSION_COOKIE=<snip>
    10. GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/phma/.gtkrc-2.0:/home/phma/.config/gtkrc-2.0
    11. KONSOLE_DBUS_SERVICE=:1.500
    12. KONSOLE_PROFILE_NAME=Shell
    13. QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
    14. GS_LIB=/home/phma/.fonts
    15. GTK_RC_FILES=/etc/gtk/gtkrc:/home/phma/.gtkrc:/home/phma/.config/gtkrc
    16. WINDOWID=310378531
    17. SHELL_SESSION_ID=<snip>
    18. XDG_SESSION_CLASS=user
    19. KDE_FULL_SESSION=true
    20. USER=phma
    21. LS_COLORS=<snip>
    22. XCURSOR_SIZE=0
    23. QT_ACCESSIBILITY=1
    24. XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session1
    25. XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
    26. SSH_AUTH_SOCK=<snip>
    27. DEFAULTS_PATH=/usr/share/gconf//usr/share/xsessions/plasma.default.path
    28. SESSION_MANAGER=<snip>
    29. XDG_CONFIG_DIRS=/etc/xdg/xdg-/usr/share/xsessions/plasma:/etc/xdg:/usr/share/kubuntu-default-settings/kf5-settings
    30. PATH=/home/phma/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
    31. DESKTOP_SESSION=/usr/share/xsessions/plasma
    32. QT_QPA_PLATFORMTHEME=appmenu-qt5
    33. QT_IM_MODULE=compose
    34. PWD=/home/phma/build/bezitopo/dbg
    35. XDG_SESSION_TYPE=x11
    36. KONSOLE_DBUS_WINDOW=/Windows/2
    37. KDE_SESSION_UID=1000
    38. LANG=en_DK.UTF-8
    39. MANDATORY_PATH=/usr/share/gconf//usr/share/xsessions/plasma.mandatory.path
    40. KONSOLE_DBUS_SESSION=/Sessions/4
    41. SHLVL=1
    42. XDG_SEAT=seat0
    43. COLORFGBG=15;0
    44. HOME=/home/phma
    45. KDE_SESSION_VERSION=5
    46. LANGUAGE=en_US:es
    47. XCURSOR_THEME=oxy-blue
    48. LOGNAME=phma
    49. XDG_SESSION_DESKTOP=KDE
    50. XDG_DATA_DIRS=/usr/share//usr/share/xsessions/plasma:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop
    51. DBUS_SESSION_BUS_ADDRESS=<snip>
    52. LESSOPEN=| /usr/bin/lesspipe %s
    53. DISPLAY=:0
    54. XDG_RUNTIME_DIR=/run/user/1000
    55. PROFILEHOME=
    56. XDG_CURRENT_DESKTOP=KDE
    57. GTK_IM_MODULE=xim
    58. LESSCLOSE=/usr/bin/lesspipe %s %s
    59. PAM_KWALLET_LOGIN=/tmp/kwallet_phma.socket
    60. XAUTHORITY=/tmp/xauth-1000-_0
    61. OLDPWD=/home/phma
    62. _=./viewtin
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Jul 2017
    Posts
    37
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: locale messes up sprintf, but only in Qt program

    Figured it out. I had to call setlocale, not setenv. The constructor of QApplication calls setlocale, but my non-Qt program was not calling setlocale, so they behave differently, which I thought was something wrong with Qt, but it isn't.

Similar Threads

  1. Adding a QListWidget messes up entire layout
    By Kasea in forum Qt Programming
    Replies: 0
    Last Post: 9th June 2017, 08:43
  2. Replies: 1
    Last Post: 31st October 2015, 17:21
  3. example for using sprintf and vsprintf in Qt-4.7.4
    By gunturrohith in forum Qt Programming
    Replies: 4
    Last Post: 8th September 2015, 10:08
  4. Sprintf in QT ?
    By wilcd in forum Newbie
    Replies: 1
    Last Post: 28th April 2012, 12:05
  5. Libcurl messes up the order of execution
    By phoenix12345 in forum Qt Programming
    Replies: 2
    Last Post: 7th September 2010, 12:14

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.