M1 Mac下GCC编译报错:wcstombs_s未定义问题求助
问题:M1 Mac + VSCode + GCC环境下
wcstombs_s函数未定义 我正在开发自定义编程语言的编译器,编写词法分析器时碰到wcstombs_s未定义的错误,已经引入了stdlib.h和stdio.h,试过修改头文件路径、调整C++标准版本、更换编译器都无法解决。
相关代码
Log.cpp
#define _CRT_SECURE_NO_WARNINGS #include "Log.h" namespace Log { LOG getlog(wchar_t logfile[]) { try { LOG struc; struc.stream = new (std::nothrow) std::ofstream; if (!struc.stream) throw ERROR_THROW(112); struc.stream->open(logfile); if (!(*(struc.stream)).is_open()) throw ERROR_THROW(112); wcscpy(struc.logfile, logfile); return struc; } catch (Error::ERROR e) { Error::ErrorDisplay(e); } } void WriteLine(LOG log, char *c, ...) { for (char **c_ptr = &c; **c_ptr; c_ptr++) { *log.stream << *c_ptr; } } void WriteLine(LOG log, wchar_t *c, ...) { unsigned lineLength = 0; char *line = nullptr; unsigned int n = 0; for (wchar_t **c_ptr = &c; **c_ptr; c_ptr++) { lineLength = wcslen(*c_ptr); line = new char[lineLength + 1]; wcstombs_s(&n, line, lineLength + 1u, *c_ptr, lineLength + 1u); *log.stream << line; delete[] line; } } void WriteLog(LOG log) { std::string line = "----Протокол------ "; time_t result = time(NULL); char str[26]; ctime_s(str, sizeof str, &result); for (int i = 0; i < 26; i++) line += str[i]; *log.stream << line; } void WriteParm(LOG log, Parm::PARM parm) { char in_text[PARM_MAX_SIZE]; char out_text[PARM_MAX_SIZE]; char log_text[PARM_MAX_SIZE]; wcstombs(in_text, parm.in, PARM_MAX_SIZE); wcstombs(out_text, parm.out, PARM_MAX_SIZE); wcstombs(log_text, parm.log, PARM_MAX_SIZE); *log.stream << "---- Параметры ---- \n-in: " << in_text << "\n-out: " << out_text << "\n-log: " << log_text; } void WriteIn(LOG log, In::IN in) { *log.stream << "\n----Исходные данные------\nКол-во символов: " << (in.size < 0 ? 0 : in.size) << std::endl << "Проигнорировано: " << (in.ignor < 0 ? 0 : in.ignor) << std::endl << "Кол-во строк: " << (in.lines < 0 ? 0 : in.lines) << std::endl; } void WriteError(LOG log, Error::ERROR error) { *log.stream << "Ошибка " << error.id << ": " << error.message << ", Строка " << error.inext.line << ", Позиция " << error.inext.col << std::endl; } void Close(LOG log) { (*log.stream).close(); delete log.stream; } }
Log.h
#pragma once #include <fstream> #include <iostream> #include <cwchar> #include <string> #include <stdlib.h> #include <stdio.h> #include "In.h" #include "Parm.h" #include "Error.h" namespace Log { struct LOG { wchar_t logfile[PARM_MAX_SIZE]; std::ofstream *stream; }; static const LOG INITLOG{L"", NULL}; LOG getlog(wchar_t logfile[]); void WriteLine(LOG log, char *c, ...); void WriteLine(LOG log, wchar_t *c, ...); void WriteLog(LOG log); void WriteParm(LOG log, Parm::PARM parm); void WriteIn(LOG log, In::IN in); void WriteError(LOG log, Error::ERROR error); void Close(LOG log); }
原因分析
wcstombs_s是微软MSVC编译器特有的安全扩展函数,不属于C/C++标准库范畴。GCC(包括M1 Mac环境下的GCC,即便你使用的是clang伪装的GCC)并不支持该函数,这就是你遇到未定义错误的核心原因。另外你代码里的ctime_s也是同理,属于MSVC专属的安全函数。
解决方案
1. 替换为标准库函数
用标准的wcstombs替代wcstombs_s,手动处理缓冲区安全:
// 替换wcstombs_s的写法 size_t converted = wcstombs(line, *c_ptr, lineLength + 1); if (converted == static_cast<size_t>(-1)) { // 处理转换失败的情况,比如设置默认值或抛出错误 strcpy(line, "[转换失败]"); }
对于ctime_s,推荐用线程安全且跨平台的strftime格式化时间:
// 替换ctime_s的写法 time_t result = time(NULL); struct tm tm_buf; localtime_r(&result, &tm_buf); char str[26]; strftime(str, sizeof(str), "%a %b %d %H:%M:%S %Y", &tm_buf);
2. 模拟实现wcstombs_s(保留原有接口)
如果想保持代码接口不变,可以在GCC环境下模拟实现该函数:
#ifdef __GNUC__ // GCC环境下模拟实现wcstombs_s errno_t wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count) { if (pReturnValue != nullptr) { *pReturnValue = wcstombs(mbstr, wcstr, sizeInBytes); } else { wcstombs(mbstr, wcstr, sizeInBytes); } // 简单处理错误,可根据实际需求调整 return (*pReturnValue == static_cast<size_t>(-1)) ? EILSEQ : 0; } #endif
将这段代码放在头文件或编译单元开头,GCC编译时会自动使用该模拟版本。
3. 编译宏启用兼容(不推荐)
部分GCC版本支持定义__STDC_WANT_LIB_EXT1__启用部分安全扩展,但M1 Mac下的GCC兼容性较差,该方法可靠性低,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者Алёша
相关产品推荐
相关产品推荐

