首页 > 解决方案 > isprint('\t') 使用 /MD 编译器选项计算结果为真 (64)

问题描述

我对isprintVisual Studio 2017 下的函数有一个意外的结果。鉴于以下程序

#include <ctype.h>
#include <stdio.h>

int main() {
  for (int i = 0; i < 128; i += 1) {
    printf("isprint(0x%x aka '%c') = %s (%d)\n", i, (char)i,
           isprint((char)i) ? "yes" : "no", isprint((char)i));
  }
  return 0;
}

使用编译和执行

cl /MD isprint.c /Feisprint.exe && isprint.exe

返回

Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26433 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

isprint.c
Microsoft (R) Incremental Linker Version 14.14.26433.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:isprint.exe
isprint.obj
isprint(0x0 aka ' ') = no (0)
isprint(0x1 aka '') = no (0)
isprint(0x2 aka '') = no (0)
isprint(0x3 aka '') = no (0)
isprint(0x4 aka '') = no (0)
isprint(0x5 aka '') = no (0)
isprint(0x6 aka '') = no (0)
isprint(0x7 aka '') = no (0)
isprint(0x8 aka ') = no (0)
isprint(0x9 aka '       ') = yes (64)
isprint(0xa aka '
') = no (0)
isprint(0xb aka '') = no (0)
isprint(0xc aka '') = no (0)
') = no (0) aka '
isprint(0xe aka '') = no (0)
isprint(0xf aka '') = no (0)
isprint(0x10 aka '') = no (0)
isprint(0x11 aka '') = no (0)
isprint(0x12 aka '') = no (0)
isprint(0x13 aka '') = no (0)
isprint(0x14 aka '') = no (0)
isprint(0x15 aka '') = no (0)
isprint(0x16 aka '') = no (0)
isprint(0x17 aka '') = no (0)
isprint(0x18 aka '') = no (0)
isprint(0x19 aka '') = no (0)
isprint(0x1a aka '') = no (0)
isprint(0x1b aka '') = no (0)
isprint(0x1c aka '') = no (0)
isprint(0x1d aka '') = no (0)
isprint(0x1e aka '') = no (0)
isprint(0x1f aka '') = no (0)
isprint(0x20 aka ' ') = yes (64)
isprint(0x21 aka '!') = yes (16)
isprint(0x22 aka '"') = yes (16)
isprint(0x23 aka '#') = yes (16)
isprint(0x24 aka '$') = yes (16)
isprint(0x25 aka '%') = yes (16)
isprint(0x26 aka '&') = yes (16)
isprint(0x27 aka ''') = yes (16)
isprint(0x28 aka '(') = yes (16)
isprint(0x29 aka ')') = yes (16)
isprint(0x2a aka '*') = yes (16)
isprint(0x2b aka '+') = yes (16)
isprint(0x2c aka ',') = yes (16)
isprint(0x2d aka '-') = yes (16)
isprint(0x2e aka '.') = yes (16)
isprint(0x2f aka '/') = yes (16)
isprint(0x30 aka '0') = yes (4)
isprint(0x31 aka '1') = yes (4)
isprint(0x32 aka '2') = yes (4)
isprint(0x33 aka '3') = yes (4)
isprint(0x34 aka '4') = yes (4)
isprint(0x35 aka '5') = yes (4)
isprint(0x36 aka '6') = yes (4)
isprint(0x37 aka '7') = yes (4)
isprint(0x38 aka '8') = yes (4)
isprint(0x39 aka '9') = yes (4)
isprint(0x3a aka ':') = yes (16)
isprint(0x3b aka ';') = yes (16)
isprint(0x3c aka '<') = yes (16)
isprint(0x3d aka '=') = yes (16)
isprint(0x3e aka '>') = yes (16)
isprint(0x3f aka '?') = yes (16)
isprint(0x40 aka '@') = yes (16)
isprint(0x41 aka 'A') = yes (1)
isprint(0x42 aka 'B') = yes (1)
isprint(0x43 aka 'C') = yes (1)
isprint(0x44 aka 'D') = yes (1)
isprint(0x45 aka 'E') = yes (1)
isprint(0x46 aka 'F') = yes (1)
isprint(0x47 aka 'G') = yes (1)
isprint(0x48 aka 'H') = yes (1)
isprint(0x49 aka 'I') = yes (1)
isprint(0x4a aka 'J') = yes (1)
isprint(0x4b aka 'K') = yes (1)
isprint(0x4c aka 'L') = yes (1)
isprint(0x4d aka 'M') = yes (1)
isprint(0x4e aka 'N') = yes (1)
isprint(0x4f aka 'O') = yes (1)
isprint(0x50 aka 'P') = yes (1)
isprint(0x51 aka 'Q') = yes (1)
isprint(0x52 aka 'R') = yes (1)
isprint(0x53 aka 'S') = yes (1)
isprint(0x54 aka 'T') = yes (1)
isprint(0x55 aka 'U') = yes (1)
isprint(0x56 aka 'V') = yes (1)
isprint(0x57 aka 'W') = yes (1)
isprint(0x58 aka 'X') = yes (1)
isprint(0x59 aka 'Y') = yes (1)
isprint(0x5a aka 'Z') = yes (1)
isprint(0x5b aka '[') = yes (16)
isprint(0x5c aka '\') = yes (16)
isprint(0x5d aka ']') = yes (16)
isprint(0x5e aka '^') = yes (16)
isprint(0x5f aka '_') = yes (16)
isprint(0x60 aka '`') = yes (16)
isprint(0x61 aka 'a') = yes (2)
isprint(0x62 aka 'b') = yes (2)
isprint(0x63 aka 'c') = yes (2)
isprint(0x64 aka 'd') = yes (2)
isprint(0x65 aka 'e') = yes (2)
isprint(0x66 aka 'f') = yes (2)
isprint(0x67 aka 'g') = yes (2)
isprint(0x68 aka 'h') = yes (2)
isprint(0x69 aka 'i') = yes (2)
isprint(0x6a aka 'j') = yes (2)
isprint(0x6b aka 'k') = yes (2)
isprint(0x6c aka 'l') = yes (2)
isprint(0x6d aka 'm') = yes (2)
isprint(0x6e aka 'n') = yes (2)
isprint(0x6f aka 'o') = yes (2)
isprint(0x70 aka 'p') = yes (2)
isprint(0x71 aka 'q') = yes (2)
isprint(0x72 aka 'r') = yes (2)
isprint(0x73 aka 's') = yes (2)
isprint(0x74 aka 't') = yes (2)
isprint(0x75 aka 'u') = yes (2)
isprint(0x76 aka 'v') = yes (2)
isprint(0x77 aka 'w') = yes (2)
isprint(0x78 aka 'x') = yes (2)
isprint(0x79 aka 'y') = yes (2)
isprint(0x7a aka 'z') = yes (2)
isprint(0x7b aka '{') = yes (16)
isprint(0x7c aka '|') = yes (16)
isprint(0x7d aka '}') = yes (16)
isprint(0x7e aka '~') = yes (16)
isprint(0x7f aka '') = no (0)

问题是它为制表符 ( ) 返回 true (64 '\t')。但是,当编译时没有/MD编译器选项或其他一些运行时库版本,例如

cl /MDd isprint.c /Feisprint.exe && isprint.exe

结果是

Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26433 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

isprint.c
Microsoft (R) Incremental Linker Version 14.14.26433.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:isprint.exe
isprint.obj
isprint(0x0 aka ' ') = no (0)
isprint(0x1 aka '') = no (0)
isprint(0x2 aka '') = no (0)
isprint(0x3 aka '') = no (0)
isprint(0x4 aka '') = no (0)
isprint(0x5 aka '') = no (0)
isprint(0x6 aka '') = no (0)
isprint(0x7 aka '') = no (0)
isprint(0x8 aka ') = no (0)
isprint(0x9 aka '       ') = no (0)
isprint(0xa aka '
') = no (0)
isprint(0xb aka '') = no (0)
isprint(0xc aka '') = no (0)
') = no (0) aka '
isprint(0xe aka '') = no (0)
isprint(0xf aka '') = no (0)
isprint(0x10 aka '') = no (0)
isprint(0x11 aka '') = no (0)
isprint(0x12 aka '') = no (0)
isprint(0x13 aka '') = no (0)
isprint(0x14 aka '') = no (0)
isprint(0x15 aka '') = no (0)
isprint(0x16 aka '') = no (0)
isprint(0x17 aka '') = no (0)
isprint(0x18 aka '') = no (0)
isprint(0x19 aka '') = no (0)
isprint(0x1a aka '') = no (0)
isprint(0x1b aka '') = no (0)
isprint(0x1c aka '') = no (0)
isprint(0x1d aka '') = no (0)
isprint(0x1e aka '') = no (0)
isprint(0x1f aka '') = no (0)
isprint(0x20 aka ' ') = yes (64)
isprint(0x21 aka '!') = yes (16)
isprint(0x22 aka '"') = yes (16)
isprint(0x23 aka '#') = yes (16)
isprint(0x24 aka '$') = yes (16)
isprint(0x25 aka '%') = yes (16)
isprint(0x26 aka '&') = yes (16)
isprint(0x27 aka ''') = yes (16)
isprint(0x28 aka '(') = yes (16)
isprint(0x29 aka ')') = yes (16)
isprint(0x2a aka '*') = yes (16)
isprint(0x2b aka '+') = yes (16)
isprint(0x2c aka ',') = yes (16)
isprint(0x2d aka '-') = yes (16)
isprint(0x2e aka '.') = yes (16)
isprint(0x2f aka '/') = yes (16)
isprint(0x30 aka '0') = yes (4)
isprint(0x31 aka '1') = yes (4)
isprint(0x32 aka '2') = yes (4)
isprint(0x33 aka '3') = yes (4)
isprint(0x34 aka '4') = yes (4)
isprint(0x35 aka '5') = yes (4)
isprint(0x36 aka '6') = yes (4)
isprint(0x37 aka '7') = yes (4)
isprint(0x38 aka '8') = yes (4)
isprint(0x39 aka '9') = yes (4)
isprint(0x3a aka ':') = yes (16)
isprint(0x3b aka ';') = yes (16)
isprint(0x3c aka '<') = yes (16)
isprint(0x3d aka '=') = yes (16)
isprint(0x3e aka '>') = yes (16)
isprint(0x3f aka '?') = yes (16)
isprint(0x40 aka '@') = yes (16)
isprint(0x41 aka 'A') = yes (1)
isprint(0x42 aka 'B') = yes (1)
isprint(0x43 aka 'C') = yes (1)
isprint(0x44 aka 'D') = yes (1)
isprint(0x45 aka 'E') = yes (1)
isprint(0x46 aka 'F') = yes (1)
isprint(0x47 aka 'G') = yes (1)
isprint(0x48 aka 'H') = yes (1)
isprint(0x49 aka 'I') = yes (1)
isprint(0x4a aka 'J') = yes (1)
isprint(0x4b aka 'K') = yes (1)
isprint(0x4c aka 'L') = yes (1)
isprint(0x4d aka 'M') = yes (1)
isprint(0x4e aka 'N') = yes (1)
isprint(0x4f aka 'O') = yes (1)
isprint(0x50 aka 'P') = yes (1)
isprint(0x51 aka 'Q') = yes (1)
isprint(0x52 aka 'R') = yes (1)
isprint(0x53 aka 'S') = yes (1)
isprint(0x54 aka 'T') = yes (1)
isprint(0x55 aka 'U') = yes (1)
isprint(0x56 aka 'V') = yes (1)
isprint(0x57 aka 'W') = yes (1)
isprint(0x58 aka 'X') = yes (1)
isprint(0x59 aka 'Y') = yes (1)
isprint(0x5a aka 'Z') = yes (1)
isprint(0x5b aka '[') = yes (16)
isprint(0x5c aka '\') = yes (16)
isprint(0x5d aka ']') = yes (16)
isprint(0x5e aka '^') = yes (16)
isprint(0x5f aka '_') = yes (16)
isprint(0x60 aka '`') = yes (16)
isprint(0x61 aka 'a') = yes (2)
isprint(0x62 aka 'b') = yes (2)
isprint(0x63 aka 'c') = yes (2)
isprint(0x64 aka 'd') = yes (2)
isprint(0x65 aka 'e') = yes (2)
isprint(0x66 aka 'f') = yes (2)
isprint(0x67 aka 'g') = yes (2)
isprint(0x68 aka 'h') = yes (2)
isprint(0x69 aka 'i') = yes (2)
isprint(0x6a aka 'j') = yes (2)
isprint(0x6b aka 'k') = yes (2)
isprint(0x6c aka 'l') = yes (2)
isprint(0x6d aka 'm') = yes (2)
isprint(0x6e aka 'n') = yes (2)
isprint(0x6f aka 'o') = yes (2)
isprint(0x70 aka 'p') = yes (2)
isprint(0x71 aka 'q') = yes (2)
isprint(0x72 aka 'r') = yes (2)
isprint(0x73 aka 's') = yes (2)
isprint(0x74 aka 't') = yes (2)
isprint(0x75 aka 'u') = yes (2)
isprint(0x76 aka 'v') = yes (2)
isprint(0x77 aka 'w') = yes (2)
isprint(0x78 aka 'x') = yes (2)
isprint(0x79 aka 'y') = yes (2)
isprint(0x7a aka 'z') = yes (2)
isprint(0x7b aka '{') = yes (16)
isprint(0x7c aka '|') = yes (16)
isprint(0x7d aka '}') = yes (16)
isprint(0x7e aka '~') = yes (16)
isprint(0x7f aka '') = no (0)

这里发生了什么?大约两周前,我注意到我的申请发生了变化。这可能是由某些 Windows 或 Visual Studio 更新引起的吗?我检查了两种情况下的线程语言环境是否相同。

Windows 10 内部版本 17134.165

标签: cvisual-c++

解决方案


@Meinersbur 感谢您报告此事。因为我只在我们的构建机器上而不是在我的工作站上看到它,所以我正在努力理解其中的区别。

为了其他人来到这里,微软的回应(见https://developercommunity.visualstudio.com/content/problem/297085/changeing-result-of-isspacet.html)是:

由 isprint() 报告为打印字符的制表符是通用 C 运行时中的回归,随着更新 KB4338819 开始出现。它将在未来的服务更新中修复,并将在 Windows 的下一个主要版本中修复。

该问题与 /MD 或 /MDd 设置无关。使用 /MD 构建时,通用 C 运行时将由 System32 中的操作系统版本提供,这将随您的操作系统版本而变化。使用 /MDd 构建时,您将收到随 Windows SDK 和 Visual Studio 一起提供的调试版本,并且您将使用已安装的最新版本。

如果您希望在所有操作系统上具有与在调试模式下看到的相同的行为,您可以通过使用 /MT 构建来静态链接 C 运行时。

希望这可以帮助!

Steve Wishnousky 软件工程师 II - Visual C++ 库


推荐阅读