C++ 跨平台

C++ 跨平台,c++,visual-c++,msvcrt,crt,C++,Visual C++,Msvcrt,Crt,我使用VisualStudioC++编译器(2010),但是库有不同的ANSI C和POSIX库函数的实现。p> ANSI C函数和Windows CRT实现之间的区别是什么?例如,tzset()和\u tzset()或setenv()ans\u setenv()之间有什么区别?看起来他们用同样的方式做同样的事情 我正在使用msvc(2010),我是否更喜欢Windows CRT实现 编辑1 我想用一种可移植的方式转换一个用UTC表示的、时间为的struct tm,但是没有可移植的方式。我必须为

我使用VisualStudioC++编译器(2010),但是库有不同的ANSI C和POSIX库函数的实现。p>

ANSI C函数和Windows CRT实现之间的区别是什么?例如,
tzset()
\u tzset()
setenv()
ans
\u setenv()
之间有什么区别?看起来他们用同样的方式做同样的事情

我正在使用msvc(2010),我是否更喜欢Windows CRT实现

编辑1

我想用一种可移植的方式转换一个用UTC表示的、时间为
的struct tm,但是没有可移植的方式。我必须为不同的平台(Android、Linux、Windows、Windows CE)编写函数

我见过使用
setenv
getenv
tzset

编辑2

不幸的是,经过一些测试,我发现
getenv(“TZ”)
在windows上返回一个空指针。但为什么将UTC时间结构转换为
时间\u t
如此困难

编辑3

在Boost中,我在Boost/chrono/io/time\u point\u io.hpp中发现了这段代码。希望这对我有帮助。

内联int32是一个飞跃(int32年)
{
如果(年份%400==0)
返回1;
如果(年份%100==0)
返回0;
如果(第%4年==0)
返回1;
返回0;
}
从0开始的内联int32天(int32年)
{
年--;
返回365*year+(year/400)-(year/100)+(year/4);
}
自1970年起的内联国际32天(国际32年)
{
从0到1970年的静态持续天数=从0到1970年的天数;
返回天数(年)-从0到1970的天数;
}
自1月1日起的内联整数日(整数年、整数月、整数日)
{
静态常数国际32天[2][12]=
{
{ 0,31,59,90,120,151,181,212,243,273,304,334},
{ 0,31,60,91,121,152,182,213,244,274,305,335}
};
返回天数[年][月-1]+日-1;
}
内联时间\u t内部时间gm(标准::tm常量*t)
{
int year=t->tm\U year+1900;
整月=t->tm月;
如果(月份>11)
{
年+=月/12;
月%=12;
}
否则,如果(月<0)
{
年际差异=(-月+11)/12;
年-=年差异;
月+=12*年_diff;
}
月份++;
int day=t->tm\u mday;
int day of年=从1月1日起的天数(年、月、日);
自新纪元起的整数天=自1970年起的天数+当年的天数;
时间-秒-日=3600*24;
时间结果=自纪元+3600*t->tm\u小时+60*t->tm\u分钟+t->tm\u秒起的秒数(以天为单位)*d;
返回结果;
}

据我所知,对于大多数函数,没有区别

名称中的下划线是为了强调这些不是标准的C函数:好吧,ANSI C中没有
tzset
setenv
函数。它们大多是POSIX函数,由MS CRT实现,以帮助从其他操作系统进行移植


但他们并不声称POSIX兼容,这就是为什么下划线。这就是为什么你应该仔细阅读微软关于这些函数的文档。。。那里有恶魔

当David Cutler的团队在1989年开始设计Windows NT时,他们还不知道哪种api将占据主导地位。所以他们创造了三个。Win32是Windows api的16位版本的改编版。OS/2是受支持的操作系统,该操作系统本应取代DOS,但没有。而POSIX则是第三,因为美国政府当时明确规定,他们只会考虑使用新兴的POSIX标准的操作系统。
您提到的tzset()函数是POSIXAPI的遗留函数。您可能拼错了putenv(),同样的故事。子系统运行得不好,Win32在api之战中大获全胜,Posix支持在2001年从Windows中删除。Microsoft保留了对Posix函数的支持,但由于Posix函数不是标准C库的一部分,因此用一个前导下划线重命名了它们。当您使用非前缀版本的函数时,应该会收到弃用警告。听起来像是您定义了CRT NONSDC NON来抑制它们。最好不要那样做。喜欢标准的C库函数。

我的
timegm
实现在windows上运行

time_t timegm(struct tm * a_tm)
{
    time_t ltime = mktime(a_tm);
    struct tm tm_val;
    gmtime_s(&tm_val, &ltime);
    int offset = (tm_val.tm_hour - a_tm->tm_hour);
    if (offset > 12)
    {
        offset = 24 - offset;
    }
    time_t utc = mktime(a_tm) - offset * 3600;
    return utc;
}

应该可以。我在Windows上使用以下宏:

#define timegm _mkgmtime
同样如此。

//算法:http://howardhinnant.github.io/date_algorithms.html
// Algorithm: http://howardhinnant.github.io/date_algorithms.html
int days_from_civil(int y, int m, int d)
{
    y -= m <= 2;
    int era = y / 400;
    int yoe = y - era * 400;                                   // [0, 399]
    int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]
    int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]
    return era * 146097 + doe - 719468;
}

time_t timegm(tm const* t)     // It  does not modify broken-down time
{
    int year = t->tm_year + 1900;
    int month = t->tm_mon;          // 0-11
    if (month > 11)
    {
        year += month / 12;
        month %= 12;
    }
    else if (month < 0)
    {
        int years_diff = (11 - month) / 12;
        year -= years_diff;
        month += 12 * years_diff;
    }
    int days_since_1970 = days_from_civil(year, month + 1, t->tm_mday);

    return 60 * (60 * (24L * days_since_1970 + t->tm_hour) + t->tm_min) + t->tm_sec;
}
从土木工程开始的整数天(整数y、整数m、整数d) { y-=m2?-3:9))+2)/5+d-1;//[0365] int doe=yoe*365+yoe/4-yoe/100+doy;//[0146096] 返回纪元*146097+doe-719468; } time\u t timegm(tm const*t)//它不修改分解时间 { int year=t->tm\U year+1900; int month=t->tm\u mon;//0-11 如果(月份>11) { 年+=月/12; 月%=12; } 否则,如果(月<0) { 年际差异=(11个月)/12; 年-=年差异; 月+=12*年_diff; } 自1970年起的整数天=自民用起的天数(年、月+1,t->tm日); 返回60*(60*(自1970年起24天+t->tm\U小时)+t->tm\U分钟)+t->tm\U秒; }
这是一种将UTC中的tm转换为时间的便携式方法


请注意,它不会修改/规范tm结构,也不会更改任何tz设置。

请参阅。另外,我认为MSVC不提供
setenv
。setenv不存在。。。但是你发现了boost代码,这很酷。这表明实现/重新实现一个100%可移植的
timegm()
(假设您不能直接使用boost)是相当容易的(而且可能是最好的主意)。注意,mingw-w64在32位上缺少这一点:对于找到这篇文章的任何R包开发人员,从@jeroen at找到一个解决方案,它不考虑非整小时偏移,例如UTC−09:30,UTC+05:45对于+/-12小时以外的时区,此操作将失败。有几个。这将在时区为的小时内失败
// Algorithm: http://howardhinnant.github.io/date_algorithms.html
int days_from_civil(int y, int m, int d)
{
    y -= m <= 2;
    int era = y / 400;
    int yoe = y - era * 400;                                   // [0, 399]
    int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]
    int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]
    return era * 146097 + doe - 719468;
}

time_t timegm(tm const* t)     // It  does not modify broken-down time
{
    int year = t->tm_year + 1900;
    int month = t->tm_mon;          // 0-11
    if (month > 11)
    {
        year += month / 12;
        month %= 12;
    }
    else if (month < 0)
    {
        int years_diff = (11 - month) / 12;
        year -= years_diff;
        month += 12 * years_diff;
    }
    int days_since_1970 = days_from_civil(year, month + 1, t->tm_mday);

    return 60 * (60 * (24L * days_since_1970 + t->tm_hour) + t->tm_min) + t->tm_sec;
}