printf, wprintf, %s, %S, %ls, char* and wchar*: Errors not announced by a compiler warning?

前端 未结 6 1861
自闭症患者
自闭症患者 2020-12-02 23:29

I have tried the following code:

wprintf(L\"1 %s\\n\",\"some string\"); //Good
wprintf(L\"2 %s\\n\",L\"some string\"); //Not good -> print only first char         


        
相关标签:
6条回答
  • 2020-12-02 23:39

    At least in Visual C++: printf (and other ACSII functions): %s represents an ASCII string %S is a Unicode string wprintf (and other Unicode functions): %s is a Unicode string %S is an ASCII string

    As far as no compiler warnings, printf uses a variable argument list, with only the first argument able to be type checked. The compiler is not designed to parse the format string and type check the parameters that match. In cases of functions like printf, that is up to the programmer

    0 讨论(0)
  • 2020-12-02 23:41

    For s: When used with printf functions, specifies a single-byte or multi-byte character string; when used with wprintf functions, specifies a wide-character string. Characters are displayed up to the first null character or until the precision value is reached.

    For S: When used with printf functions, specifies a wide-character string; when used with wprintf functions, specifies a single-byte or multi-byte character string. Characters are displayed up to the first null character or until the precision value is reached.

    In Unix-like platform, s and S have the same meaning as windows platform.

    Reference: https://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx

    0 讨论(0)
  • 2020-12-02 23:42

    %S seems to conform to The Single Unix Specification v2 and is also part of the current (2008) POSIX specification.

    Equivalent C99 conforming format specifiers would be %s and %ls.

    0 讨论(0)
  • 2020-12-02 23:48

    I suspect GCC (mingw) has custom code to disable the checks for the wide printf functions on Windows. This is because Microsoft's own implementation (MSVCRT) is badly wrong and has %s and %ls backwards for the wide printf functions; since GCC can't be sure whether you will be linking with MS's broken implementation or some corrected one, the least-obtrusive thing it can do is just shut off the warning.

    0 讨论(0)
  • 2020-12-02 23:54

    The format specifers matter: "%s" says that the next string is a narrow string ("ascii" and typically 8 bits per character). "%S" means wide char string. Mixing the two will give "undefined behaviour", which includes printing garbage, just one character or nothing.

    One character is printed because wide chars are, for example, 16 bits wide, and the first byte is non-zero, followed by a zero byte -> end of string in narrow strings. This depends on byte-order, in a "big endian" machine, you'd get no string at all, because the first byte is zero, and the next byte contains a non-zero value.

    0 讨论(0)
  • 2020-12-02 23:54

    Answer A

    None of the answers above pointed out why you might not see some of your prints. This is also because here you are dealing with streams (I didn't know this) and stream has something called orientation. Let me cite something from this source:

    Narrow and wide orientation

    A newly opened stream has no orientation. The first call to any I/O function establishes the orientation.

    A wide I/O function makes the stream wide-oriented, a narrow I/O function makes the stream narrow-oriented. Once set, the orientation can only be changed with freopen.

    Narrow I/O functions cannot be called on a wide-oriented stream; wide I/O functions cannot be called on a narrow-oriented stream. Wide I/O functions convert between wide and multibyte characters as if by calling mbrtowc and wcrtomb. Unlike the multibyte character strings that are valid in a program, multibyte character sequences in the file may contain embedded nulls and do not have to begin or end in the initial shift state.

    So once you use printf() your orientation becomes narrow and from this point on you can't get anything out of wprintf() and you realy don't. Unless you use freeopen() which is intended to be used on files.


    Answer B

    As it turns out you can use freeopen() like this:

    freopen(NULL, "w", stdout);             
    

    To make stream "not defined" again. Try this example:

    #include <stdio.h>
    #include <wchar.h>
    #include <locale.h>
    
    int main(void)
    {
        // We set locale which is the same as the enviromental variable "LANG=en_US.UTF-8".
        setlocale(LC_ALL, "en_US.UTF-8");
    
        // We define array of wide characters. We indicate this on both sides of equal sign
        // with "wchar_t" on the left and "L" on the right.
        wchar_t y[100] = L"                                                                    
    0 讨论(0)
提交回复
热议问题