C语言的结构体内存对齐又三条原则 如下:
①数据成员对齐规则:
结构体的数据成员中,第一个成员从offset为0的地址开始,以后每一个成员存储的起始位置为该成员大小的整数倍
②结构体作为成员:
如果一个结构体1作为另一个结构体2的数据成员,则在结构体2中结构体1要从1内部成员最大的整数倍地址开始存储。
③结构体的总大小(sizeof):
为该结构体内部最大基本类型的整数倍,不足的要补齐,而不是简单的所有成员的大小总和。
如果结构体不满足对齐规则,编译器会又自动补齐机制(除非强制对齐.)
这个问题会导致在你以后操作中的一些不可预料错误.
最近学习python时自己制作了一个小工具检查结构体成员是否对齐.代码如下:
import traceback
listScannedFile = []
dirtScannedMacro = {}
listDefinedMacro = []
class ReadFileEndError(Exception):
"""Read File End"""
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
def ScanStructInit():
dirtScannedMacro['unsigned int'] = 4
dirtScannedMacro['unsigned char'] = 1
dirtScannedMacro['int'] = 4
dirtScannedMacro['char'] = 1
dirtScannedMacro['short'] = 2
dirtScannedMacro['unsigned short'] = 2
def getCount(strLine):
try:
while True:
pos = strLine.find('sizeof(')
if -1 != pos:
rpos = strLine.find(')', pos+7)
strMacro = strLine[pos+7:rpos]
strLine = strLine[0:pos] + str(dirtScannedMacro[strMacro]) + strLine[rpos+1:]
else:
break
listStrMacro = []
strTemp = ""
bIsLeftFind = 0
for i in range(len(strLine)):
if not bIsLeftFind:
if strLine[i].isalpha() or '_' == strLine[i]:
strTemp += strLine[i]
bIsLeftFind = 1
else:
if strLine[i].isalpha() or strLine[i].isdigit() or '_' == strLine[i]:
strTemp += strLine[i]
else:
bIsLeftFind = 0
listStrMacro.append(strTemp)
strTemp = ""
if 1 == bIsLeftFind:
listStrMacro.append(strTemp)
strTemp = ""
for strTemp in listStrMacro:
strLine = strLine.replace(strTemp, str(dirtScannedMacro[strTemp]))
return eval(strLine)
except:
traceback.print_exc()
def ReadLineNotSpace(fileHandle):
try:
while True:
strLine = fileHandle.readline()
if not strLine:
raise ReadFileEndError('Read File Finish')
strLine = strLine[0:strLine.find(r'//')].rstrip()
if strLine:
return strLine
except:
raise
def ReadLineNoNote(fileHandle):
try:
while True:
strLine = ReadLineNotSpace(fileHandle)
while True:
if not strLine.strip():
break
posLeft = strLine.find(r'/*')
if -1 == posLeft:
return strLine.rstrip()
strNoteLine = strLine[posLeft+2:]
strLine = strLine[0:posLeft]
while True:
posRight = strNoteLine.find(r'*/')
if -1 == posRight:
strNoteLine = ReadLineNotSpace(fileHandle)
else:
strLine += strNoteLine[posRight+2:]
break
except:
raise
def ReadACompleteLine(fileHandle):
try:
strLine = ReadLineNoNote(fileHandle)
while True:
if '\\' != strLine[-1]:
return strLine.strip()
else:
strLine = strLine.rstrip('\\')
strLine += ReadLineNoNote(fileHandle)
except:
raise
def ScanInclude(strLine):
try:
pos = strLine.find('#include', 0, 8)
if -1 == pos:
return
strLine = strLine[8:].strip()
if '"' != strLine[0] and '<' != strLine[0]:
return
strLine = strLine[1:-1]
if strLine:
ScanFile(strLine)
except:
traceback.print_exc()
def ScanDefine(strLine):
try:
pos = strLine.find('#define', 0, 7)
if -1 == pos:
return
if ' ' != strLine[7] and '\t' != strLine[7]:
return
strLine = strLine[7:].strip()
strLine = ' '.join(strLine.split())
pos = strLine.find(' ')
if -1 == pos:
listDefinedMacro.append(strLine)
else:
marcoName = strLine[0:pos]
marcoValue = strLine[pos+1:]
if marcoValue in dirtScannedMacro:
dirtScannedMacro[marcoName] = dirtScannedMacro[marcoValue]
else:
dirtScannedMacro[marcoName] = marcoValue
except:
traceback.print_exc()
def ScanEnum(strLine, fileHandle):
try:
pos = strLine.find('typedef enum', 0, 12)
if -1 == pos:
return
strLine = strLine[12:].strip()
while True:
pos = strLine.find('{')
if -1 == pos:
strLine = ReadACompleteLine(fileHandle)
else:
strLine = strLine[pos+1:].strip()
break
while True:
pos = strLine.find('}')
if -1 == pos:
strLine += ReadACompleteLine(fileHandle)
else:
strLine = strLine[0:pos].strip()
break
enumList = strLine.split(',')
iValue = 0
for strEnum in enumList:
pos = strEnum.find('=')
if -1 == pos:
dirtScannedMacro[strEnum.strip()] = iValue
else:
strName = strEnum[0:pos].strip()
strValue = strEnum[pos+1:].strip()
if strValue in dirtScannedMacro:
dirtScannedMacro[strName] = dirtScannedMacro[strValue]
iValue = int(dirtScannedMacro[strValue])
else:
iValue = int(strValue)
dirtScannedMacro[strName] = iValue
iValue += 1
return
except ReadFileEndError:
raise
except:
traceback.print_exc()
def AnalysisStruct(listSize, listCount):
try:
iSum = 0
for i in range(len(listSize)):
if iSum:
iSum += listSize[i]*listCount[i]
continue
else:
if listSize[i] > 8 and 0 != iSum % 8:
return i
if 0 != iSum % listSize[i]:
return i
iSum += listSize[i]*listCount[i]
if 0 != (iSum % 8):
return -1
return 0
except:
traceback.print_exc()
def ScanStruct(strLine, fileHandle):
try:
pos = strLine.find('typedef struct', 0, 14)
if -1 == pos:
return
strLine = strLine[14:]
while True:
pos = strLine.find('{')
if -1 == pos:
strLine = ReadACompleteLine(fileHandle)
else:
strLine = strLine[pos+1:].strip()
break
while True:
pos = strLine.find('}')
if -1 == pos:
strLine += ReadACompleteLine(fileHandle)
else:
strLine = strLine[0:pos].strip()
break
listStruct = strLine.split(';')
listStructSize = []
listStructCount = []
for strStruct in listStruct:
strStruct = strStruct.strip()
if not strStruct:
continue
strName = strStruct.split()[0]
strValue = strStruct[len(strName):].strip()
if '*' == strName[-1] or '*' == strValue[0]:
listStructSize.append(8)
else:
listStructSize.append(int(dirtScannedMacro[strName]))
pos = strValue.find('[')
if -1 == pos:
listStructCount.append(1)
else:
iCount = getCount(strValue[pos+1:-1].strip())
if iCount <= 0:
print("Struct Error iCount:%d" % (iCount))
return
listStructCount.append(iCount)
iRet = AnalysisStruct(listStructSize, listStructCount)
if 0 != iRet:
print('Error Struct. iRet:%d' % iRet)
except ReadFileEndError as ex:
raise
except:
traceback.print_exc()
def ScanFile(fileName):
if fileName in listScannedFile:
return 0
print("ScanFile %s" % (fileName))
listScannedFile.append(fileName)
try:
fileHandle = open(fileName, 'r')
while True:
strLine = ReadACompleteLine(fileHandle)
#print("read a line:%s, %d" % (strLine, len(strLine)))
ScanInclude(strLine)
ScanDefine(strLine)
ScanEnum(strLine, fileHandle)
ScanStruct(strLine, fileHandle)
except ReadFileEndError as ex:
print("Scan File %s Finished!" % (fileName))
fileHandle.close()
except IOError as ex:
pass
except:
traceback.print_exc()
return 0
if __name__ == '__main__':
ScanStructInit()
ScanFile('main.c')