#ifndef GETFILEHANDLE_H__
#define GETFILEHANDLE_H__
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS 0x00000000
#define STATUS_UNSUCCESSFUL 0xC0000001
#define STATUS_NOT_IMPLEMENTED 0xC0000002
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004//
//#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_ACCESS_DENIED 0xC0000022
#define STATUSBUFFER_TOO_SMALL 0xC0000023
#define STATUS_BUFFER_OVERFLOW 0x80000005
//#define OBJ_KERNEL_HANDLE 0x00000200
//#define SystemModuleInformation 11
//#define SystemHandleInformation 0x10
//typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWST Buffer; } UNICODE_STRING, *PUNICODE_STRING;
//typedef enum _PROCESSINFOCLASS { ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters ProcessTimes, ProcessBasePriority, ProcessRaisePriority, ProcessDebugPort, ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, ProcessWow64Information, ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, ProcessBreakOnTermination, ProcessDebugObjectHandle, ProcessDebugFlags, ProcessHandleTracing, ProcessUnknown33, ProcessUnknown34, ProcessUnknown35, ProcessCookie, MaxProcessInfoClass } PROCESSINFOCLASS;
//typedef NTSTATUS(WINAPI *PFN_ZwQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
//typedef NTSTATUS(WINAPI *PFN_IoVolumeDeviceToDosName)(PVOID VolumeDeviceObject, PUNICODE_STRING DosName);
//int main(int argn, TCHAR argv[]){
// HMODULE hDll = LoadLibrary(_T("Ntdll.dll")); PFN_ZwQueryInformationProcess pFn_ZwQueryInformationProcess; PFN_IoVolumeDeviceToDosName pFn_IoVolumeDeviceToDosName; if (NULL != hDll) { pFn_ZwQueryInformationProcess = (PFN_ZwQueryInformationProcess)GetProcAddress(hDll, "ZwQueryInformationProcess"); if (NULL != pFn_ZwQueryInformationProcess) { printf("Found it!!!ZwQueryInformationProcess\n"); }pFn_IoVolumeDeviceToDosName = (PFN_IoVolumeDeviceToDosName)GetProcAddress(hDll, "IoVolumeDeviceToDosName"); if (NULL != pFn_IoVolumeDeviceToDosName) { printf("Found it!!!IoVolumeDeviceToDosName\n"); } }
// PROCESSINFOCLASS aFileName = ProcessImageFileName; UNICODE_STRING usRet; ULONG ulRet; HANDLE hProcess = GetCurrentProcess(); NTSTATUS stRet = pFn_ZwQueryInformationProcess(hProcess, aFileName, &usRet, 0, &ulRet);
// if (stRet == STATUS_INFO_LENGTH_MISMATCH){
// usRet.Length = ulRet; usRet.MaximumLength = ulRet;//usRet.Buffer = (TCHAR*)malloc(sizeof(TCHAR) * (ulRet) );}
// stRet = pFn_ZwQueryInformationProcess(hProcess, aFileName, &usRet, ulRet, &ulRet); if (NT_SUCCESS(stRet)){ _tprintf(TEXT("FileName:%s\n"), usRet.Buffer); } if (NULL != hDll) { FreeLibrary(hDll); hDll = NULL; }if (NULL != usRet.Buffer)free(usRet.Buffer); _tsystem(TEXT("pause")); return 0;
// }
//
typedef struct _SYSTEM_HANDLE
{
ULONG uIdProcess;
UCHAR ObjectType; // OB_TYPE_* (OB_TYPE_TYPE, etc.)
UCHAR Flags; // HANDLE_FLAG_* (HANDLE_FLAG_INHERIT, etc.)
USHORT Handle;
PVOID pObject;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG uCount;
SYSTEM_HANDLE aSH[];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef enum _SYSTEMINFOCLASS
{
SystemBasicInformation1, // 0x002C
SystemProcessorInformation, // 0x000C
SystemPerformanceInformation1, // 0x0138
SystemTimeInformation, // 0x0020
SystemPathInformation, // not implemented
SystemProcessInformation1, // 0x00C8+ per process
SystemCallInformation, // 0x0018 + (n * 0x0004)
SystemConfigurationInformation, // 0x0018
SystemProcessorCounters, // 0x0030 per cpu
SystemGlobalFlag, // 0x0004 (fails if size != 4)
SystemCallTimeInformation, // not implemented
SystemModuleInformation, // 0x0004 + (n * 0x011C)
SystemLockInformation, // 0x0004 + (n * 0x0024)
SystemStackTraceInformation, // not implemented
SystemPagedPoolInformation, // checked build only
SystemNonPagedPoolInformation, // checked build only
SystemHandleInformation, // 0x0004 + (n * 0x0010)
SystemObjectTypeInformation, // 0x0038+ + (n * 0x0030+)
SystemPageFileInformation, // 0x0018+ per page file
SystemVdmInstemulInformation, // 0x0088
SystemVdmBopInformation, // invalid info class
SystemCacheInformation, // 0x0024
SystemPoolTagInformation, // 0x0004 + (n * 0x001C)
SystemInterruptInformation1, // 0x0000, or 0x0018 per cpu
SystemDpcInformation, // 0x0014
SystemFullMemoryInformation, // checked build only
SystemLoadDriver, // 0x0018, set mode only
SystemUnloadDriver, // 0x0004, set mode only
SystemTimeAdjustmentInformation, // 0x000C, 0x0008 writeable
SystemSummaryMemoryInformation, // checked build only
SystemNextEventIdInformation, // checked build only
SystemEventIdsInformation, // checked build only
SystemCrashDumpInformation, // 0x0004
SystemExceptionInformation1, // 0x0010
SystemCrashDumpStateInformation, // 0x0004
SystemDebuggerInformation, // 0x0002
SystemContextSwitchInformation, // 0x0030
SystemRegistryQuotaInformation1, // 0x000C
SystemAddDriver, // 0x0008, set mode only
SystemPrioritySeparationInformation,// 0x0004, set mode only
SystemPlugPlayBusInformation, // not implemented
SystemDockInformation, // not implemented
SystemPowerInfo, // 0x0060 (XP only!)
SystemProcessorSpeedInformation, // 0x000C (XP only!)
SystemTimeZoneInformation, // 0x00AC
SystemLookasideInformation1, // n * 0x0020
SystemSetTimeSlipEvent,
SystemCreateSession, // set mode only
SystemDeleteSession, // set mode only
SystemInvalidInfoClass1, // invalid info class
SystemRangeStartInformation, // 0x0004 (fails if size != 4)
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation, // checked build only
MaxSystemInfoClass
} SYSTEMINFOCLASS, *PSYSTEMINFOCLASS;
typedef NTSTATUS(WINAPI *ZWQUERYSYSTEMINFORMATION)(unsigned long, PVOID, ULONG, PULONG);
NTSTATUS
ZwQuerySystemInformation(
IN SYSTEMINFOCLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
typedef struct _NM_INFO
{
HANDLE hFile;
FILE_NAME_INFORMATION Info;
WCHAR Name[MAX_PATH];
} NM_INFO, *PNM_INFO;
typedef enum _FILE_INFORMATION_CLASS1 {
FileDirectoryInformation1 = 1,
FileFullDirectoryInformation,
FileBothDirectoryInformation,
FileBasicInformation,
FileStandardInformation,
FileInternalInformation,
FileEaInformation,
FileAccessInformation,
FileNameInformation,
FileRenameInformation,
FileLinkInformation,
FileNamesInformation,
FileDispositionInformation,
FilePositionInformation,
FileFullEaInformation,
FileModeInformation,
FileAlignmentInformation,
FileAllInformation,
FileAllocationInformation,
FileEndOfFileInformation,
FileAlternateNameInformation,
FileStreamInformation,
FilePipeInformation,
FilePipeLocalInformation,
FilePipeRemoteInformation,
FileMailslotQueryInformation,
FileMailslotSetInformation,
FileCompressionInformation,
FileCopyOnWriteInformation,
FileCompletionInformation,
FileMoveClusterInformation,
FileQuotaInformation,
FileReparsePointInformation,
FileNetworkOpenInformation,
FileObjectIdInformation,
FileTrackingInformation,
FileOleDirectoryInformation,
FileContentIndexInformation,
FileInheritContentIndexInformation,
FileOleInformation,
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef NTSTATUS(WINAPI *ZWQUERYINFORMATIONFILE)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG,
FILE_INFORMATION_CLASS);
NTSTATUS
ZwQueryInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
typedef struct _OBJECT_NAME_INFORMATION {
WORD Length;
WORD MaximumLength;
LPWSTR Buffer;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef long(__stdcall*PNtQueryObject)(HANDLE ObjectHandle, ULONG ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength);
typedef enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllInformation,
ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
BOOL AdjustProcessPrivilege(HANDLE hProcess, LPCTSTR lpPrivilegeName, DWORD dwPrivilegeAttribute);
void GetProcessNameById(DWORD dwId, string& szName);
void GetProcessIdByName(LPCSTR szName, vector<DWORD>& vID);
void GetOpenFileByPid(DWORD pid, vector<string> &vFiles);
void GetPidByOpenFile(const string& szFilePath, vector<DWORD> &vPid);
#endif
GetFileHandle.cpp
// GetFileHandle.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "GetFileHandle.h"
void GetProcessNameById(DWORD dwId,string& szName)
{
DWORD ParentProcessID = -1;
PROCESSENTRY32 pe;
HANDLE hkz;
HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));
if (hModule == NULL)
{
OutputDebugString(_T("Load dll error"));
return;
}
FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");
if (Address == NULL)
{
OutputDebugString(_T("Get Proc error"));
return;
}
_asm
{
push 0
push 2; TH32CS_SNAPPROCESS
call Address
mov hkz, eax
}
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hkz, &pe))
{
do
{
//if (pe.th32ProcessID == pid)//进程ID找到
//{
// ParentProcessID = pe.th32ParentProcessID;
// break;
//}
if (dwId == pe.th32ProcessID)
{
szName = pe.szExeFile;
}
} while (Process32Next(hkz, &pe));
}
return;
}
void GetProcessIdByName(LPCSTR szName,vector<DWORD>& vID)
{
DWORD ParentProcessID = -1;
PROCESSENTRY32 pe;
HANDLE hkz;
HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));
if (hModule == NULL)
{
OutputDebugString(_T("Load dll error"));
return ;
}
FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");
if (Address == NULL)
{
OutputDebugString(_T("Get Proc error"));
return ;
}
_asm
{
push 0
push 2
call Address
mov hkz, eax
}
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hkz, &pe))
{
do
{
//if (pe.th32ProcessID == pid)//进程ID找到
//{
// ParentProcessID = pe.th32ParentProcessID;
// break;
//}
if (0 == strcmp(pe.szExeFile,szName))
{
vID.push_back(pe.th32ProcessID);
}
} while (Process32Next(hkz, &pe));
}
return ;
}
BOOL AdjustProcessPrivilege(HANDLE hProcess, LPCTSTR lpPrivilegeName, DWORD dwPrivilegeAttribute)
{
BOOL bRetValue = FALSE;
HANDLE hProcessToken;
//如果hProcess是NULL,说明调用者想要调整当前进程的权限,使用GetCurrentProcess获得的进程句柄无需关闭
HANDLE hOpenProcess = (hProcess != NULL) ? hProcess : GetCurrentProcess();
//打开进程令牌,期望的权限为可以调整权限和查询,得到进程令牌句柄
if (OpenProcessToken(hOpenProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken) != FALSE)
{
LUID stPrivilegeLuid;
//通过权限名称,查找指定的权限的LUID值
if (LookupPrivilegeValue(NULL, lpPrivilegeName, &stPrivilegeLuid) != FALSE)
{
//设置新的权限
TOKEN_PRIVILEGES stNewTokenPrivilege;
stNewTokenPrivilege.PrivilegeCount = 1;
stNewTokenPrivilege.Privileges[0].Luid = stPrivilegeLuid;
stNewTokenPrivilege.Privileges[0].Attributes = dwPrivilegeAttribute;
//调整权限
if (AdjustTokenPrivileges(hProcessToken, FALSE, &stNewTokenPrivilege, sizeof(stNewTokenPrivilege), NULL, NULL) != FALSE)
{
bRetValue = TRUE;
}
}
//关闭进程令牌句柄
CloseHandle(hProcessToken);
}
return bRetValue;
}
PVOID GetInfoTable(IN ULONG ATableType)
{
ULONG mSize = 0x8000;
PVOID mPtr;
NTSTATUS status;
HANDLE hHeap = GetProcessHeap();
do
{
mPtr = HeapAlloc(hHeap, 0, mSize);
if (!mPtr) return NULL;
memset(mPtr, 0, mSize);
HMODULE hNtDLL = LoadLibrary("NTDLL.DLL");
if (!hNtDLL)
{
return FALSE;
}
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDLL, "ZwQuerySystemInformation");
if (ZwQuerySystemInformation == NULL)
{
return FALSE;
}
status = ZwQuerySystemInformation(ATableType, mPtr, mSize, NULL);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
HeapFree(hHeap, 0, mPtr);
mSize = mSize * 2;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
if (NT_SUCCESS(status)) return mPtr;
HeapFree(hHeap, 0, mPtr);
return NULL;
}
//DWORD WINAPI GetFileNameThread(PVOID lpParameter)
//{
// PNM_INFO NmInfo = (PNM_INFO)lpParameter;
// IO_STATUS_BLOCK IoStatus;
//
// HMODULE hNtDLL = LoadLibrary("NTDLL.DLL");
// if (!hNtDLL)
// {
// return FALSE;
// }
// ZWQUERYINFORMATIONFILE ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtDLL, "ZwQueryInformationFile");
// if (ZwQueryInformationFile == NULL)
// {
// return FALSE;
// }
// FILE_NAME_INFORMATION fni;
// DWORD dwRet=ZwQueryInformationFile(NmInfo->hFile, &IoStatus, &NmInfo->Info, sizeof(NM_INFO)-sizeof(HANDLE), (FILE_INFORMATION_CLASS)FileNameInformation);
// if (NT_SUCCESS(dwRet))
// {
// return 1;
// }
// return 0;
//}
string ChangePathToDevice(const string& szFilePath)
{
string szRoot = szFilePath.substr(0, 2);
string szTmp = szFilePath.substr(2, szFilePath.length() - 2);
char cBuf[MAX_PATH] = { 0 };
DWORD dwRet = QueryDosDevice(szRoot.c_str(), cBuf, MAX_PATH);
string szRet = cBuf;
szRet += szTmp;
return szRet;
}
wstring GetMSDosPathByHandle(HANDLE hFile)
{
wstring szRet;
PNtQueryObject NtQueryObject(reinterpret_cast<PNtQueryObject>(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryObject")));
if (NtQueryObject)
{
OBJECT_NAME_INFORMATION name, *pname; ULONG len;
NTSTATUS status = NtQueryObject(hFile, ObjectNameInformation, &name, sizeof name, &len);
if (STATUS_BUFFER_OVERFLOW == status)
{
pname = reinterpret_cast<POBJECT_NAME_INFORMATION>(new char[len]);
status = NtQueryObject(hFile, ObjectNameInformation, pname, len, &len);
if (SUCCEEDED(status))
{
szRet = pname->Buffer;
}
delete pname;
}
}
return szRet;
}
DWORD WINAPI GetFileNameThread2(PVOID lpParameter)
{
PNM_INFO NmInfo = (PNM_INFO)lpParameter;
wstring szRet = GetMSDosPathByHandle(NmInfo->hFile);
NmInfo->Info.FileNameLength = szRet.size();
wcscpy(NmInfo->Info.FileName, szRet.c_str());
return 0;
}
void GetFileName(HANDLE hFile, PCHAR TheName)
{
HANDLE hThread;
HANDLE hHeap = GetProcessHeap();
PNM_INFO Info = (PNM_INFO)HeapAlloc(hHeap, 0, sizeof(NM_INFO));
Info->hFile = hFile;
hThread = CreateThread(NULL, 0, GetFileNameThread2, Info, 0, NULL);
if (WaitForSingleObject(hThread, 100) == WAIT_TIMEOUT) TerminateThread(hThread, 0);
CloseHandle(hThread);
memset(TheName, 0, MAX_PATH);
//wprintf(Info->Info.FileName);
//printf("\n");
WideCharToMultiByte(CP_ACP, 0, Info->Info.FileName, Info->Info.FileNameLength , TheName, MAX_PATH, NULL, NULL);
HeapFree(hHeap, 0, Info);
}
UCHAR GetFileHandleType()
{
HANDLE hFile;
PSYSTEM_HANDLE_INFORMATION Info;
ULONG r;
UCHAR Result = 0;
HANDLE hHeap = GetProcessHeap();
hFile = CreateFile("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
Info = (PSYSTEM_HANDLE_INFORMATION)GetInfoTable(SystemHandleInformation);
if (Info)
{
for (r = 0; r < Info->uCount; r++)
{
if (Info->aSH[r].Handle == (USHORT)hFile &&
Info->aSH[r].uIdProcess == GetCurrentProcessId())
{
Result = Info->aSH[r].ObjectType;
break;
}
}
HeapFree(hHeap, 0, Info);
}
CloseHandle(hFile);
}
return Result;
}
void GetOpenFileByPid(DWORD pid, vector<string> &vFiles)
{
// 取得操作系统文件句柄定义类型
UCHAR ObFileType = GetFileHandleType();
//获取进程中的句柄
PSYSTEM_HANDLE_INFORMATION Info;
ULONG r;
CHAR Name[MAX_PATH];
HANDLE hProcess, hFile;
HANDLE hHeap = GetProcessHeap();
Info = (PSYSTEM_HANDLE_INFORMATION)GetInfoTable(SystemHandleInformation);
if (Info)
{
for (r = 0; r < Info->uCount; r++)
{
if (Info->aSH[r].ObjectType == ObFileType && Info->aSH[r].uIdProcess == pid)
{
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, Info->aSH[r].uIdProcess);
if (hProcess)
{
if (DuplicateHandle(hProcess, (HANDLE)Info->aSH[r].Handle, GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
GetFileName(hFile, Name);
vFiles.push_back(Name);
CloseHandle(hFile);
}
}
}
}
HeapFree(hHeap, 0, Info);
}
}
void GetPidByOpenFile(const string& szFilePath, vector<DWORD> &vPid)
{
string szTmp =ChangePathToDevice(szFilePath);
// 取得操作系统文件句柄定义类型
UCHAR ObFileType = GetFileHandleType();
//获取进程中的句柄
PSYSTEM_HANDLE_INFORMATION Info;
ULONG r;
CHAR Name[MAX_PATH];
HANDLE hProcess, hFile;
HANDLE hHeap = GetProcessHeap();
Info = (PSYSTEM_HANDLE_INFORMATION)GetInfoTable(SystemHandleInformation);
if (Info)
{
for (r = 0; r < Info->uCount; r++)
{
if (Info->aSH[r].ObjectType == ObFileType )
{
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, Info->aSH[r].uIdProcess);
if (hProcess)
{
if (DuplicateHandle(hProcess, (HANDLE)Info->aSH[r].Handle, GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
GetFileName(hFile, Name);
if (szTmp == Name)
{
vPid.push_back(Info->aSH[r].uIdProcess);
}
CloseHandle(hFile);
}
}
}
}
HeapFree(hHeap, 0, Info);
}
}
///////////////////////////////////////////////////////////////
上面代码为2015.02.09编译,原因是ZwQueryInformationFile查询得到的路径没有盘符,改用了NtQueryObject,防止C:\\1.txt被误认为D:\\2.txt。
此外还有更重要的原因,就是下次直接去博客找可用代码,不用重复发明轮子了,算是开放svn吧。
///////////////////////////////////////////////////////////////
标题很二,不过应该程序员会明白,这个就是我需要的,就够了。
经常遇到一些问题,比如:通过进程ID确定进程名,通过进程名确定进程ID。windows通常只提供一种查询,然后全部枚举一遍,自己建立反向查询映射关系。
为了给后来人提供参考,也为了自己不用再次发明轮子,或者找不到轮子的时候,在这里做备忘录。代码是整理别人的,API是微软发明的,就像小麦是农民种的,面粉是工厂磨的,但是有人蒸出来馒头,是不是给你省了很多事儿?或者,如果你有一颗感恩的心,就不会说“xxx我已经知道了,没啥了不起的”,就像“馒头我自己会蒸,你的馒头我就不花钱了”。呵呵,开源精神在中国养活一大批白眼狼,端子碗筷吃饭,放下碗筷骂娘,念完经打和尚,吃饱了就骂厨子……咳咳,扯远了,他们都是领导干部,得罪不起,就当我什么都没说。
里面也不用添加注释了,里面函数名和变量名就起到了自注释的作用,相信C语言二级通过的人都会看得懂。
最后吐槽几句,我听过两种截然相反的论调:1.没有注释价值的代码,就没有书写的价值。2.好的代码无需注释,具有自我解释的功能。呵呵,你TMD在逗我吗?叫我们程序员怎么办?其实这两句话都是有自己的背景,也就是“上下文环境”,单独抽离出来以偏概全,这个是我大天朝理论界的普遍招数,希望程序员界不要被污染。前一句是C++发明之前,C,Pascal这种面向过程作为主要生产语言的时代,不信你打开C的头文件,基本满满的注释,一个API十几个参数,鬼才知道怎么用,不注释谁看得懂?后一句是Java,.Net发明之后的才兴起的,面向对象可以把大的函数包装成一个一个小的函数,把十几个参数的组合,分别包装成不同成员函数,这样顾名思义,把一个API十几个参数,变成十几个API,用一个对象把数据管理起来,这样方便复用,也有了“快速迭代”的基础,要不然每个轮子都要自己设计,快速迭代个屁。
所以,规则是死的,人是活的,陷入非是既非的宗教狂热是不能成为好程序员的,就像Unix阵营和Windows阵营互相攻击那样的没有意义,天朝子民长期被洗脑,我们程序员最早接触西方世界文明,希望能够率先摆脱洗脑的后遗症。