吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1009|回复: 10
收起左侧

[已解决] C语言调用WriteFile函数向txt文件写入8个中文字符串,但txt文件却显示4个

[复制链接]
mxwawaawxm 发表于 2022-7-20 22:24
本帖最后由 mxwawaawxm 于 2022-7-24 11:19 编辑

[C] 纯文本查看 复制代码
#include <windows.h>
#include <tchar.h>

void SaveFileData(PCTSTR szFileName, LPCVOID szFileData, DWORD dwNumberOfBytesToWrite);

int WINAPI WinMain(HINSTANCE hHinstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    PCTSTR szFileData = TEXT("这是一个例子。");
    PCTSTR szFileName = TEXT("d:\\test\\1.txt");

    SaveFileData(szFileName, szFileData, (DWORD)sizeof(szFileData));
    _tprintf(TEXT("%I64u\n"), sizeof(szFileData));

    return 0;
}

void SaveFileData(PCTSTR szFileName, LPCVOID szFileData, DWORD dwNumberOfBytesToWrite)
{
    // 文件句柄
    HANDLE hFileWrite;
    // 成功写入的数据大小
    DWORD dwNumberOfBytesWritten;

    // 打开文件
    hFileWrite = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // 判断是否打开成功
    if (hFileWrite==INVALID_HANDLE_VALUE) {
        _tprintf(TEXT("打开 %s 文件失败。错误代码是:%lu。\n"), szFileName, GetLastError());
    } else{
        // 设置文件指针到文件末
        SetFilePointer(hFileWrite, 0, 0, FILE_END);
        // 写入文件
        if (!WriteFile(hFileWrite, szFileData, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, NULL)) {
            _tprintf(TEXT("写入 %s 文件失败。错误代码是:%lu。\n"), szFileName, GetLastError());
        } else {
            _tprintf(TEXT("写入 %s 文件成功。写入的字节总数:%lu。\n"), szFileName, dwNumberOfBytesWritten);
        }
    }
    CloseHandle(hFileWrite);
}

代码如上。请大佬们看看。
运行结果如下

写入的数据定义在这里,PCTSTR szFileData = TEXT("这是一个例子。");
这个字符串有8个字符。我特意用sizeof(szFileData)计算了长度,并打印出来了。
结果显示8,但文本文件只显示4个字符。

我经过排查,发现是WriteFile函数的第3个参数,不能用sizeof(szFileData),而应该用lstrlen(szFileData)获得的长度。这样才能正确写入。
sizeof(szFileData)和lstrlen(szFileData)得出的长度居然很不一样。一个是14,一个是8。
请问大佬们,为什么WriteFile函数的第三个参数不能用sizeof(szFileData),而要用lstrlen(szFileData)。谢谢。

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

田田爱崽崽 发表于 2022-7-20 22:30
本帖最后由 田田爱崽崽 于 2022-7-20 22:32 编辑

一个汉语字符是占两字节呀,没有毛病呀

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-20 22:45
田田爱崽崽 发表于 2022-7-20 22:30
一个汉语字符是占两字节呀,没有毛病呀

谢谢
洒家好像明白一点点了
PCTSTR szFileData = TEXT("这是一个例子。");
lstrlen(szFileData) = 14
去除掉最后的\0所占的两个字节,刚好是14字节。
而sizeof(szFileData)获取的是指针的长度,因为洒家是64位系统,所以是8字节
洒家误以为sizeof(szFileData)是获取字符数组的长度
刚好PCTSTR szFileData = TEXT("这是一个例子。");,也是8个字符
爱飞的猫 发表于 2022-7-21 04:22
本帖最后由 爱飞的猫 于 2022-7-21 04:24 编辑

补充一下:

strlen 取出来的不是字符串的字符数量是从给定指针开始到 00 结束时的字节数量。

strlen interprets the string as a single-byte character string, so its return value is always equal to the number of bytes, even if the string contains multibyte characters.

另外如果是 Unicode 字符串,应使用 wcslen(pStr) * sizeof(wchar_t) 得出字节数量。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

忘了带钱 发表于 2022-7-21 09:35
sizeof(指针);在32位系统下返回4;在64位系统下返回8;
应该用 strlen() 函数来获取字符串指针的长度;

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-21 09:36
本帖最后由 mxwawaawxm 于 2022-7-21 09:37 编辑
爱飞的猫 发表于 2022-7-21 04:22
[md]补充一下:

`strlen` 取出来的不是字符串的字符数量是从给定指针开始到 00 结束时的字节数量。

谢谢大佬。
PCTSTR szFileData = TEXT("这是一个例子。");
这样定义了字符指针后,获取字符串的长度
这么写 lstrlen(szFileData) * sizeof(TCHAR)
这样更准确,是吗?
如果是Unicode 字符串,自动转换成wcslen(pStr) * sizeof(wchar_t)
如果是ANSI字符串,转换成strlen(pStr) * sizeof(char)

点评

[md]对的,这个 API 的选择是编译时决定的。 `tchar.h` 提供的对应函数其实是 `_tcslen`。你能够在头文件看到这个函数根据 `_UNICODE` 是否定义而选择 `strlen` 或 `wcslen`。 相关文档: https://docs.mic  详情 回复 发表于 2022-7-21 16:09
爱飞的猫 发表于 2022-7-21 16:09
本帖最后由 爱飞的猫 于 2022-7-21 16:32 编辑
mxwawaawxm 发表于 2022-7-21 09:36
谢谢大佬。
PCTSTR szFileData = TEXT("这是一个例子。");
这样定义了字符指针后,获取字符串的长度

对的,这个 API 的选择是编译时决定的。

tchar.h 提供的对应函数其实是 _tcslen。你能够在头文件看到这个函数根据 _UNICODE 是否定义而选择 strlenwcslen
这个函数明确说明了在 ANSI 的情况下是一个字节一个字节来数 CHAR 数量(strlen interprets the string as a single-byte character string, so its return value is always equal to the number of bytes, even if the string contains multibyte characters),而 Unicode 的情况下数 WCHAR 数量。

lstrlen 的文档未对此进行说明,只是提到了返回 character 的数量;但实际测试的结果也表明它与 strlen 的结果一致。

需要注意「字节数量」与「字符数量」,因为 strlen 会将「中文」将算作 4 个字节,而 _mbslen 函数会将其算作 2 个字符。

#include <Windows.h> // 提供 lstrlen
#include <stdio.h>
#include <tchar.h>
#include <mbstring.h>
#include <locale.h>

int main()
{
    // 注意返回的是 size_t,在 32/64 位下分别是 u32/u64。
    printf("strlen(中文) = %zu\n", strlen("中文"));
    printf("wcslen(中文) = %zu\n", wcslen(L"中文"));

    printf("tcslen(中文) * sizeof(TCHAR) = %zu\n", _tcslen(TEXT("中文")) * sizeof(TCHAR));

    // 数"文字字符"数量
    _locale_t locale = _create_locale(LC_ALL, "zh-CN");
    printf("_mbslen_l(中文, zh-CN) = %zu\n", _mbslen_l(reinterpret_cast<const unsigned char*>("中文"), locale));
    printf("_mbslen(中文) = %zu\n", _mbslen(reinterpret_cast<const unsigned char*>("中文")));

    // 返回的是 32 位的 int
    printf("lstrlenA(中文) = %d\n", lstrlenA("中文"));
    printf("lstrlenW(中文) = %d\n", lstrlenW(L"中文"));
}
strlen(中文) = 4
wcslen(中文) = 2
tcslen(中文) * sizeof(TCHAR) = 4
_mbslen_l(中文, zh-CN) = 2
_mbslen(中文) = 2
lstrlenA(中文) = 4
lstrlenW(中文) = 2

相关文档:

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-21 22:18
爱飞的猫 发表于 2022-7-21 16:09
[md]对的,这个 API 的选择是编译时决定的。

`tchar.h` 提供的对应函数其实是 `_tcslen`。你能够在头 ...

谢谢大佬。
我这边%zu不能正确打印_tcslen等函数获取的长度
总是提示
[Asm] 纯文本查看 复制代码
unknown conversion type character 'z' in format [-Wformat=]

我都得换成%I64u,才能正确打印size_t类型(其实就是long long unsigned int)的数值

另外中间reinterpret_cast,好像是C++的语法。C语言不是直接这样就可以强制类型转换了。
[C] 纯文本查看 复制代码
printf("_mbslen(中文) = %I64u\n", _mbslen((const unsigned char *)("中文")));

点评

感觉可能和 vs 版本有关,我用的是 vs2022… 也有可能 c 使用编译器有一些不同? reinterprete_cast 确实是 c++ 的,我给忘了…  详情 回复 发表于 2022-7-21 22:20
爱飞的猫 发表于 2022-7-21 22:20
mxwawaawxm 发表于 2022-7-21 22:18
谢谢大佬。
我这边%zu不能正确打印_tcslen等函数获取的长度
总是提示

感觉可能和 vs 版本有关,我用的是 vs2022… 也有可能 c 使用编译器有一些不同?

reinterprete_cast 确实是 c++ 的,我给忘了…

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-7-27 21:55
爱飞的猫 发表于 2022-7-21 22:20
感觉可能和 vs 版本有关,我用的是 vs2022… 也有可能 c 使用编译器有一些不同?

reinterprete_cast  ...

大佬,请问下,关于wsprintf这个函数,tchar.h对应提供的函数是什么?
感觉wsprintf和sprintf函数差不多(两个函数应该的区别是:单字节/双字节字符)
但又怎么还设置了wsprintfA(应该是针对ANSI)和wsprintfW函数(针对宽字符串)。

点评

看文档: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/sprintf-sprintf-l-swprintf-swprintf-l-swprintf-l?view=msvc-170 sprintf 对应的 tchar.h 函数是 “_stprintf” --- wsp  详情 回复 发表于 2022-7-29 02:37
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止回复与主题无关非技术内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-9 06:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表