实验一:

先在VS2017上编译白易模块(下面这里仅演示debug_static版)

 

然后我们把该模块导入到VS2019的工程中

接着主项目的运行时改为多线程调试:

由于配置了/MT(d),在工程下该_DLL的宏变为未定义,于是走static的版本

关于这些预定义宏的说明:VC中_DLL,_LIB等预定义的宏.mht

正常编译后是没报什么警告或错误信息:


当然如果仅是std::cout可能过于简单,且常规的new/delete我也测了并没有报错

 

接下来我再让AI生成更复杂的案例:

AI给的代码如下:

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <fstream>
#include <exception>

// 测试跨模块内存管理冲突的函数
extern "C" {
__declspec(dllexport) void* allocate_in_lib(size_t size);
__declspec(dllexport) void free_in_lib(void* ptr);
__declspec(dllexport) std::string* create_string_in_lib();
__declspec(dllexport) void destroy_string_in_lib(std::string* str);
}

// 在当前模块中实现这些函数
void* allocate_in_lib(size_t size) {
return malloc(size);
}

void free_in_lib(void* ptr) {
free(ptr);
}

std::string* create_string_in_lib() {
return new std::string("Created in VS2017 module");
}

void destroy_string_in_lib(std::string* str) {
delete str;
}

以上编译到VS2017的模块中
// 测试异常跨边界的函数
class CustomException : public std::exception {
private:
std::string message;
public:
CustomException(const std::string& msg) : message(msg) {}
const char* what() const noexcept override {
return message.c_str();
}
};

void throw_exception_from_lib() {
throw CustomException("Exception from VS2017 module");
}

// 测试IO操作的函数
void test_file_operations() {
std::ofstream file("test_vs2017.txt");
file << "Hello from VS2017 CRT" << std::endl;
file.close();

std::ifstream infile("test_vs2017.txt");
std::string content;
std::getline(infile, content);
infile.close();

std::cout << "File content: " << content << std::endl;
}

// 测试STL容器的跨模块使用
std::vector<int>* create_vector_in_lib() {
auto* vec = new std::vector<int>{ 1, 2, 3, 4, 5 };
return vec;
}

void destroy_vector_in_lib(std::vector<int>* vec) {
delete vec;
}

void run() {
std::cout << "VS2017 CRT Test Program" << std::endl;

// 测试1: 基本内存分配/释放
void* ptr = allocate_in_lib(100);
if (ptr) {
std::cout << "Memory allocated in lib: " << ptr << std::endl;
free_in_lib(ptr);
}

// 测试2: string对象的创建和销毁
std::string* str = create_string_in_lib();
if (str) {
std::cout << "String from lib: " << *str << std::endl;
destroy_string_in_lib(str);
}

// 测试3: 异常处理
try {
throw_exception_from_lib();
} catch (const CustomException& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}

// 测试4: 文件IO操作
test_file_operations();

// 测试5: STL容器
std::vector<int>* vec = create_vector_in_lib();
if (vec) {
std::cout << "Vector size: " << vec->size() << std::endl;
for (const auto& item : *vec) {
std::cout << "Item: " << item << std::endl;
}
destroy_vector_in_lib(vec);
}

// 测试6: 智能指针跨模块使用
auto shared_ptr = std::make_shared<int>(42);
std::cout << "Shared pointer value: " << *shared_ptr << std::endl;
std::cout << "Shared pointer use count: " << shared_ptr.use_count() << std::endl;

// 测试7: 静态对象初始化顺序
static int static_var = []() {
std::cout << "Static variable initialized in VS2017 module" << std::endl;
return 100;
}();

std::cout << "Static variable value: " << static_var << std::endl;

std::cout << "Program completed successfully" << std::endl;
}

然后我放到VS2019中编译生成(注意run部分的代码要单独放VS2019中,不然测试没意义):

至此,我们可以简单测出,对于复杂情况即便是从VS2017发布的debug版静态库,移植到VS2019中debug工程去链接使用也是没有问题的!

 

 


实验二:

还有一类问题,

虽然不同CRT段中的静态库(VC140之后)可能本身没有什么ABI问题,但CRT在进行设置的时候它们有可能维护的一些全局状态就会存在“多份应用级副本”

下面是微软官方列举出了可能的CRT全局态受影响的C库函数

 

注意:只是说可能,不过实际情况是我后来做了下更正(其实这也是实验一完全不会有问题的根本原因!,下面要做的实验二本质也是如此)

而且事实上,你在VS2017编译lib静态库(/MTd,声明为CRT是静态库),而主程VS2019为/MDd(声明CRT为动态库),直接报错是肯定的(引入的C/C++运行时lib名就完全不一致,链接阶段官方直接给出错误):

不过我们下面还是可以测试一下这种涉及全局CRT状态的复杂案例上,VS2017编译lib静态库(/MTd),而主程VS2019也为/MTd会有问题不?

 

接着我让AI继续生成测试用例:

// 这个文件将编译成VS2017静态库(声明的CRT为动态库),测试全局状态函数

#include
<iostream>

#include <locale.h>
#include <exception>
#include <new>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <iomanip>

// 测试locale设置
void vs2017_set_locale() {
std::cout << "=== VS2017 Setting Locale ===" << std::endl;

// 设置为德语区域
setlocale(LC_ALL, "German_Germany.1252");

// 测试数字格式
double number = 1234.56;
printf("VS2017: German locale number: %.2f\n", number);

// 测试时间格式
time_t now = time(nullptr);
struct tm* timeinfo = localtime(&now);
char buffer[80];
strftime(buffer, sizeof(buffer), "%A, %d %B %Y", timeinfo);
printf("VS2017: German date: %s\n", buffer);

// 验证当前locale
const char* current_locale = setlocale(LC_ALL, nullptr);
printf("VS2017: Current locale: %s\n", current_locale ? current_locale : "NULL");
}

// 测试异常处理器
void vs2017_set_terminate_handler() {
std::cout << "\n=== VS2017 Setting Terminate Handler ===" << std::endl;

static bool vs2017_handler_called = false;

auto old_handler = std::set_terminate([]() {
std::cout << "VS2017: Custom terminate handler called!" << std::endl;
vs2017_handler_called = true;
std::abort();
});

std::cout << "VS2017: Terminate handler set" << std::endl;
std::cout << "VS2017: Previous handler was: " << (old_handler ? "set" : "null") << std::endl;
}

// 测试new_handler
void vs2017_set_new_handler() {
std::cout << "\n=== VS2017 Setting New Handler ===" << std::endl;

static bool vs2017_new_handler_called = false;

auto old_handler = std::set_new_handler([]() {
std::cout << "VS2017: Custom new handler called!" << std::endl;
vs2017_new_handler_called = true;
throw std::bad_alloc();
});

std::cout << "VS2017: New handler set" << std::endl;
std::cout << "VS2017: Previous new handler was: " << (old_handler ? "set" : "null") << std::endl;
}

// 测试环境变量
void vs2017_set_environment() {
std::cout << "\n=== VS2017 Setting Environment ===" << std::endl;

// 设置环境变量
int result = _putenv("VS2017_VAR=FromVS2017CRT");
std::cout << "VS2017: _putenv result: " << result << std::endl;

// 读取环境变量
char* env_value = getenv("VS2017_VAR");
std::cout << "VS2017: VS2017_VAR = " << (env_value ? env_value : "NULL") << std::endl;

// 设置另一个变量
_putenv("SHARED_VAR=VS2017_Setting");
env_value = getenv("SHARED_VAR");
std::cout << "VS2017: SHARED_VAR = " << (env_value ? env_value : "NULL") << std::endl;
}

// 测试时区设置
void vs2017_set_timezone() {
std::cout << "\n=== VS2017 Setting Timezone ===" << std::endl;

// 设置时区
_putenv("TZ=PST8PDT");
tzset();

// 显示时区信息
time_t now = time(nullptr);
struct tm* timeinfo = localtime(&now);

std::cout << "VS2017: Timezone set to PST" << std::endl;
// tm_gmtoff不是标准C++,使用timezone代替
long timezone_diff = _timezone;
std::cout << "VS2017: Current time offset: " << timezone_diff << " seconds" << std::endl;
std::cout << "VS2017: Daylight saving: " << (timeinfo->tm_isdst ? "Yes" : "No") << std::endl;
}

// 综合测试函数
void vs2017_global_state_test() {
std::cout << "=== VS2017 Global State Test Started ===" << std::endl;

vs2017_set_locale();
vs2017_set_terminate_handler();
vs2017_set_new_handler();
vs2017_set_environment();
vs2017_set_timezone();

std::cout << "\n=== VS2017 Global State Test Completed ===" << std::endl;
}

// 检查当前状态的函数
void vs2017_check_current_state() {
std::cout << "\n=== VS2017 Checking Current State ===" << std::endl;

// 检查locale
const char* current_locale = setlocale(LC_ALL, nullptr);
std::cout << "VS2017: Current locale: " << (current_locale ? current_locale : "NULL") << std::endl;

// 检查环境变量
char* vs2017_var = getenv("VS2017_VAR");
char* shared_var = getenv("SHARED_VAR");
char* vs2019_var = getenv("VS2019_VAR");

std::cout << "VS2017: VS2017_VAR = " << (vs2017_var ? vs2017_var : "NULL") << std::endl;
std::cout << "VS2017: SHARED_VAR = " << (shared_var ? shared_var : "NULL") << std::endl;
std::cout << "VS2017: VS2019_VAR = " << (vs2019_var ? vs2019_var : "NULL") << std::endl;

// 检查数字格式
double test_number = 1234.56;
std::cout << "VS2017: Number format test: " << test_number << std::endl;
}
// VS2019主程序,将调用VS2017库并测试全局状态冲突


#include <iostream>
#include <locale.h>
#include <exception>
#include <new>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <iomanip>

// 声明VS2017库中的函数
void vs2017_global_state_test();
void vs2017_check_current_state();

// VS2019特有的全局状态测试函数
void vs2019_set_locale() {
   std::cout << "=== VS2019 Setting Locale ===" << std::endl;
   
   // 设置为法语区域
   setlocale(LC_ALL, "French_France.1252");
   
   // 测试数字格式
   double number = 1234.56;
   printf("VS2019: French locale number: %.2f\n", number);
   
   // 测试时间格式
   time_t now = time(nullptr);
   struct tm* timeinfo = localtime(&now);
   char buffer[80];
   strftime(buffer, sizeof(buffer), "%A, %d %B %Y", timeinfo);
   printf("VS2019: French date: %s\n", buffer);
   
   // 验证当前locale
   const char* current_locale = setlocale(LC_ALL, nullptr);
   printf("VS2019: Current locale: %s\n", current_locale ? current_locale : "NULL");
}

void vs2019_set_terminate_handler() {
   std::cout << "\n=== VS2019 Setting Terminate Handler ===" << std::endl;
   
   static bool vs2019_handler_called = false;
   
   auto old_handler = std::set_terminate([]() {
       std::cout << "VS2019: Custom terminate handler called!" << std::endl;
       vs2019_handler_called = true;
       std::abort();
   });
   
   std::cout << "VS2019: Terminate handler set" << std::endl;
   std::cout << "VS2019: Previous handler was: " << (old_handler ? "set" : "null") << std::endl;
}

void vs2019_set_new_handler() {
   std::cout << "\n=== VS2019 Setting New Handler ===" << std::endl;
   
   static bool vs2019_new_handler_called = false;
   
   auto old_handler = std::set_new_handler([]() {
       std::cout << "VS2019: Custom new handler called!" << std::endl;
       vs2019_new_handler_called = true;
       throw std::bad_alloc();
   });
   
   std::cout << "VS2019: New handler set" << std::endl;
   std::cout << "VS2019: Previous new handler was: " << (old_handler ? "set" : "null") << std::endl;
}

void vs2019_set_environment() {
   std::cout << "\n=== VS2019 Setting Environment ===" << std::endl;
   
   // 设置环境变量
   int result = _putenv("VS2019_VAR=FromVS2019CRT");
   std::cout << "VS2019: _putenv result: " << result << std::endl;
   
   // 读取环境变量
   char* env_value = getenv("VS2019_VAR");
   std::cout << "VS2019: VS2019_VAR = " << (env_value ? env_value : "NULL") << std::endl;
   
   // 修改共享变量
   _putenv("SHARED_VAR=VS2019_Modified");
   env_value = getenv("SHARED_VAR");
   std::cout << "VS2019: SHARED_VAR = " << (env_value ? env_value : "NULL") << std::endl;
}

void vs2019_set_timezone() {
   std::cout << "\n=== VS2019 Setting Timezone ===" << std::endl;
   
   // 设置不同时区
   _putenv("TZ=EST5EDT");
   tzset();
   
   // 显示时区信息
   time_t now = time(nullptr);
   struct tm* timeinfo = localtime(&now);
   
   std::cout << "VS2019: Timezone set to EST" << std::endl;
   // tm_gmtoff不是标准C++,使用timezone代替
   long timezone_diff = _timezone;
   std::cout << "VS2019: Current time offset: " << timezone_diff << " seconds" << std::endl;
   std::cout << "VS2019: Daylight saving: " << (timeinfo->tm_isdst ? "Yes" : "No") << std::endl;
}

void vs2019_global_state_test() {
   std::cout << "=== VS2019 Global State Test Started ===" << std::endl;
   
   vs2019_set_locale();
   vs2019_set_terminate_handler();
   vs2019_set_new_handler();
   vs2019_set_environment();
   vs2019_set_timezone();
   
   std::cout << "\n=== VS2019 Global State Test Completed ===" << std::endl;
}

void vs2019_check_current_state() {
   std::cout << "\n=== VS2019 Checking Current State ===" << std::endl;
   
   // 检查locale
   const char* current_locale = setlocale(LC_ALL, nullptr);
   std::cout << "VS2019: Current locale: " << (current_locale ? current_locale : "NULL") << std::endl;
   
   // 检查环境变量
   char* vs2017_var = getenv("VS2017_VAR");
   char* shared_var = getenv("SHARED_VAR");
   char* vs2019_var = getenv("VS2019_VAR");
   
   std::cout << "VS2019: VS2017_VAR = " << (vs2017_var ? vs2017_var : "NULL") << std::endl;
   std::cout << "VS2019: SHARED_VAR = " << (shared_var ? shared_var : "NULL") << std::endl;
   std::cout << "VS2019: VS2019_VAR = " << (vs2019_var ? vs2019_var : "NULL") << std::endl;
   
   // 检查数字格式
   double test_number = 1234.56;
   std::cout << "VS2019: Number format test: " << test_number << std::endl;
}

int main() {
   std::cout << "=== Global State Conflict Test ===" << std::endl;
   std::cout << "Testing CRT global state sharing between VS2017 and VS2019" << std::endl;
   
   // 步骤1: VS2019设置自己的全局状态
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "STEP 1: VS2019 Setting Initial Global State" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   vs2019_global_state_test();
   vs2019_check_current_state();
   
   // 步骤2: 调用VS2017库,让它修改全局状态
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "STEP 2: Calling VS2017 Library" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   vs2017_global_state_test();
   
   // 步骤3: VS2019检查全局状态是否被影响
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "STEP 3: VS2019 Checking State After VS2017 Call" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   vs2019_check_current_state();
   
   // 步骤4: 让VS2017也检查当前状态
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "STEP 4: VS2017 Checking Current State" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   vs2017_check_current_state();
   
   // 步骤5: VS2019再次修改状态,观察是否影响VS2017
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "STEP 5: VS2019 Modifying State Again" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   // 修改locale为英语
   setlocale(LC_ALL, "English_United States.1252");
   _putenv("FINAL_VAR=VS2019_Final");
   
   std::cout << "VS2019: Set locale to English and added FINAL_VAR" << std::endl;
   
   // 最终检查
   std::cout << "\n" << std::string(60, '=') << std::endl;
   std::cout << "FINAL STATE CHECK" << std::endl;
   std::cout << std::string(60, '=') << std::endl;
   
   vs2019_check_current_state();
   vs2017_check_current_state();
   
   std::cout << "\n=== Test Conclusions ===" << std::endl;
   std::cout << "If global state is shared:" << std::endl;
   std::cout << "- VS2017 and VS2019 should see the same locale" << std::endl;
   std::cout << "- Environment variables should be visible to both" << std::endl;
   std::cout << "- Timezone changes should affect both" << std::endl;
   std::cout << "\nIf global state is separate:" << std::endl;
   std::cout << "- Each CRT should maintain its own state" << std::endl;
   std::cout << "- Changes in one should not affect the other" << std::endl;
   
   return 0;
}
测试完输出结果:

=== Global State Conflict Test ===
Testing CRT global state sharing between VS2017 and VS2019
 
============================================================
STEP 1: VS2019 Setting Initial Global State
============================================================
=== VS2019 Global State Test Started ===
=== VS2019 Setting Locale ===
VS2019: French locale number: 1234,56
VS2019: French date: jeudi, 19 mars 2026
VS2019: Current locale: French_France.1252
 
=== VS2019 Setting Terminate Handler ===
VS2019: Terminate handler set
VS2019: Previous handler was: set
 
=== VS2019 Setting New Handler ===
VS2019: New handler set
VS2019: Previous new handler was: null
 
=== VS2019 Setting Environment ===
VS2019: _putenv result: 0
VS2019: VS2019_VAR = FromVS2019CRT
VS2019: SHARED_VAR = VS2019_Modified
 
=== VS2019 Setting Timezone ===
VS2019: Timezone set to EST
VS2019: Current time offset: 18000 seconds
VS2019: Daylight saving: Yes
 
=== VS2019 Global State Test Completed ===
 
=== VS2019 Checking Current State ===
VS2019: Current locale: French_France.1252
VS2019: VS2017_VAR = NULL
VS2019: SHARED_VAR = VS2019_Modified
VS2019: VS2019_VAR = FromVS2019CRT
VS2019: Number format test: 1234.56
 
============================================================
STEP 2: Calling VS2017 Library
============================================================
=== VS2017 Global State Test Started ===
=== VS2017 Setting Locale ===
VS2017: German locale number: 1234,56
VS2017: German date: Donnerstag, 19 M?rz 2026
VS2017: Current locale: German_Germany.1252
 
=== VS2017 Setting Terminate Handler ===
VS2017: Terminate handler set
VS2017: Previous handler was: set
 
=== VS2017 Setting New Handler ===
VS2017: New handler set
VS2017: Previous new handler was: set
 
=== VS2017 Setting Environment ===
VS2017: _putenv result: 0
VS2017: VS2017_VAR = FromVS2017CRT
VS2017: SHARED_VAR = VS2017_Setting
 
=== VS2017 Setting Timezone ===
VS2017: Timezone set to PST
VS2017: Current time offset: 28800 seconds
VS2017: Daylight saving: Yes
 
=== VS2017 Global State Test Completed ===
 
============================================================
STEP 3: VS2019 Checking State After VS2017 Call
============================================================
 
=== VS2019 Checking Current State ===
VS2019: Current locale: German_Germany.1252
VS2019: VS2017_VAR = FromVS2017CRT
VS2019: SHARED_VAR = VS2017_Setting
VS2019: VS2019_VAR = FromVS2019CRT
VS2019: Number format test: 1234.56
 
============================================================
STEP 4: VS2017 Checking Current State
============================================================
 
=== VS2017 Checking Current State ===
VS2017: Current locale: German_Germany.1252
VS2017: VS2017_VAR = FromVS2017CRT
VS2017: SHARED_VAR = VS2017_Setting
VS2017: VS2019_VAR = FromVS2019CRT
VS2017: Number format test: 1234.56
 
============================================================
STEP 5: VS2019 Modifying State Again
============================================================
VS2019: Set locale to English and added FINAL_VAR
 
============================================================
FINAL STATE CHECK
============================================================
 
=== VS2019 Checking Current State ===
VS2019: Current locale: English_United States.1252
VS2019: VS2017_VAR = FromVS2017CRT
VS2019: SHARED_VAR = VS2017_Setting
VS2019: VS2019_VAR = FromVS2019CRT
VS2019: Number format test: 1234.56
 
=== VS2017 Checking Current State ===
VS2017: Current locale: English_United States.1252
VS2017: VS2017_VAR = FromVS2017CRT
VS2017: SHARED_VAR = VS2017_Setting
VS2017: VS2019_VAR = FromVS2019CRT
VS2017: Number format test: 1234.56
 
=== Test Conclusions ===
If global state is shared:
- VS2017 and VS2019 should see the same locale
- Environment variables should be visible to both
- Timezone changes should affect both
 
If global state is separate:
- Each CRT should maintain its own state
- Changes in one should not affect the other

我直接让AI分析完报告后并给我来段总结:

 

上边只是测了,纯静态库的版本(对跨VS版本的CRT静态库上是没问题的),那其实还可以测一下主程是声明CRT静态库下,去用动态库编译的模块会怎么样?这个我放在另起一个文章的实验场景中:

主程为CRT动态库引入不同VS的动态库但其自身静态CRT的模块.mht