1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-27 09:33:42 +00:00

Merge pull request #401 from greg-king5/void-size

Make C's sizeof operator work with cc65's void variables.
This commit is contained in:
Oliver Schmidt 2017-03-12 20:06:34 +01:00 committed by GitHub
commit 0bbe4f56a5
7 changed files with 147 additions and 62 deletions

View File

@ -4,7 +4,7 @@
<title>cc65 Users Guide <title>cc65 Users Guide
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline> <author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:gregdk@users.sf.net" name="Greg King"> <url url="mailto:gregdk@users.sf.net" name="Greg King">
<date>2016-06-11 <date>2017-02-27
<abstract> <abstract>
cc65 is a C compiler for 6502 targets. It supports several 6502 based home cc65 is a C compiler for 6502 targets. It supports several 6502 based home
@ -687,30 +687,37 @@ This cc65 version has some extensions to the ISO C standard.
string. string.
<p> <p>
<item> cc65 allows the initialization of <tt/void/ variables. This may be <item> cc65 allows the initialization of <tt/void/ variables. This may be
used to create variable structures that are more compatible with used to create arbitrary structures that are more compatible with
interfaces written for assembler languages. Here is an example: interfaces written for assembler languages. Here is an example:
<tscreen><verb> <tscreen><verb>
void GCmd = { (char)3, (unsigned)0x2000, (unsigned)0x3000 }; void GCmd = { (char)3, (unsigned)0x2000, (unsigned)0x3000 };
</verb></tscreen> </verb></tscreen>
This will be translated as follows: That will be translated as follows:
<tscreen><verb> <tscreen><verb>
_GCmd: _GCmd:
.byte 3 .byte 3
.word $2000 .word $2000
.word $3000 .word $3000
</verb></tscreen> </verb></tscreen>
Since the variable is of type <tt/void/ you may not use it as is. Since the variable is of type <tt/void/, you may not use it as-is.
However, taking the address of the variable results in a <tt/void*/ However, taking the address of the variable results in a <tt/void*/
which may be passed to any function expecting a pointer. which may be passed to any function expecting a pointer. Also, the
<tt/sizeof/ operator will give the length of the initializer:
See the <url url="geos.html" name="GEOS library document"> for examples <tscreen><verb>
on how to use this feature. GLen = sizeof GCmd;
<p> </verb></tscreen>
will assign the value 5 to <tt/GLen/.
See the <url url="geos.html" name="GEOS library document"> for examples
on how to use that feature.
<p>
<item> cc65 implements flexible array struct members as defined in the C99 ISO <item> cc65 implements flexible array struct members as defined in the C99 ISO
standard. As an extension, these fields may be initialized. There are standard. As an extension, these fields may be initialized. There are

View File

@ -389,7 +389,10 @@ unsigned SizeOf (const Type* T)
switch (UnqualifiedType (T->C)) { switch (UnqualifiedType (T->C)) {
case T_VOID: case T_VOID:
return 0; /* Assume voids have size zero */ /* A void variable is a cc65 extension.
** Get its size (in bytes).
*/
return T->A.U;
/* Beware: There's a chance that this triggers problems in other parts /* Beware: There's a chance that this triggers problems in other parts
of the compiler. The solution is to fix the callers, because calling of the compiler. The solution is to fix the callers, because calling
@ -438,7 +441,7 @@ unsigned SizeOf (const Type* T)
/* Array with unspecified size */ /* Array with unspecified size */
return 0; return 0;
} else { } else {
return T->A.L * SizeOf (T + 1); return T->A.U * SizeOf (T + 1);
} }
default: default:

View File

@ -891,6 +891,7 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
case TOK_VOID: case TOK_VOID:
NextToken (); NextToken ();
D->Type[0].C = T_VOID; D->Type[0].C = T_VOID;
D->Type[0].A.U = 0;
D->Type[1].C = T_END; D->Type[1].C = T_END;
break; break;
@ -2114,7 +2115,7 @@ NextMember:
static unsigned ParseVoidInit (void) static unsigned ParseVoidInit (Type* T)
/* Parse an initialization of a void variable (special cc65 extension). /* Parse an initialization of a void variable (special cc65 extension).
** Return the number of bytes initialized. ** Return the number of bytes initialized.
*/ */
@ -2181,6 +2182,9 @@ static unsigned ParseVoidInit (void)
/* Closing brace */ /* Closing brace */
ConsumeRCurly (); ConsumeRCurly ();
/* Number of bytes determined by initializer */
T->A.U = Size;
/* Return the number of bytes initialized */ /* Return the number of bytes initialized */
return Size; return Size;
} }
@ -2216,8 +2220,8 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
case T_VOID: case T_VOID:
if (IS_Get (&Standard) == STD_CC65) { if (IS_Get (&Standard) == STD_CC65) {
/* Special cc65 extension in non ANSI mode */ /* Special cc65 extension in non-ANSI mode */
return ParseVoidInit (); return ParseVoidInit (T);
} }
/* FALLTHROUGH */ /* FALLTHROUGH */

9
test/err/void-empty.c Normal file
View File

@ -0,0 +1,9 @@
/*
!!DESCRIPTION!! Uninitialized void variables
!!ORIGIN!! cc65 regression tests
!!LICENCE!! Public Domain
!!AUTHOR!! Greg King
*/
void test;
const void list;

11
test/err/void-size2.c Normal file
View File

@ -0,0 +1,11 @@
/*
!!DESCRIPTION!! Size of void cast
!!ORIGIN!! cc65 regression tests
!!LICENCE!! Public Domain
!!AUTHOR!! Greg King
*/
unsigned test (void)
{
return sizeof ((void)12345);
}

56
test/val/void-size1.c Normal file
View File

@ -0,0 +1,56 @@
/*
!!DESCRIPTION!! Getting the size of a void-type variable (cc65 extension)
!!ORIGIN!! cc65 regression tests
!!LICENCE!! Public Domain
!!AUTHOR!! Greg King
*/
static const void list1 = {
(char)1,
(char)2,
(char)3,
(char)4,
(char)5,
(char)6,
(char)7,
(char)8,
(char)9,
(char)0
};
static void list2 = {
1,
2,
3,
4,
5,
6,
7,
8,
9,
0
};
void list3 = {
(char)1,
(char)2,
(char)3,
(char)4,
&list1,
(char)6,
(char)7,
(char)8,
(char)9,
&list2
};
/* We know that the expression is constant; don't tell us. */
#pragma warn (const-comparison, off)
int main (void)
{
return sizeof list1 != 10
|| sizeof list2 != 20
|| sizeof list3 != 12;
}

View File

@ -1,59 +1,55 @@
/* /*
** testprogram for ANTIC instructions as defined in "_antic.h" ** test program for ANTIC instructions as defined in "_antic.h"
** **
** 23-Feb-2017, Christian Krueger ** 23-Feb-2017, Christian Krueger
*/ */
#include <conio.h> #include <conio.h>
#include <atari.h> #include <atari.h>
#include <peekpoke.h>
#include <string.h>
// code is only for testing purposes, as screen and display list are not aligned // code is only for testing purposes, as screen and display list are not aligned,
// and jumps not set! // and jumps not set!
unsigned char DummyScreen[400]; unsigned char DummyScreen[400];
void DisplayList = { void DisplayList = {
DL_BLK1, DL_BLK1,
DL_BLK2, DL_BLK2,
DL_BLK3, DL_BLK3,
DL_BLK4, DL_BLK4,
DL_BLK5, DL_BLK5,
DL_BLK6, DL_BLK6,
DL_BLK7, DL_BLK7,
DL_DLI(DL_BLK8), DL_DLI(DL_BLK8),
DL_LMS(DL_CHR40x8x1), DL_LMS(DL_CHR40x8x1),
DummyScreen, DummyScreen,
DL_HSCROL(DL_CHR40x10x1), DL_HSCROL(DL_CHR40x10x1),
DL_VSCROL(DL_CHR40x8x4), DL_VSCROL(DL_CHR40x8x4),
DL_CHR40x16x4, DL_CHR40x16x4,
DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))), DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))),
DummyScreen+120, DummyScreen+120,
DL_CHR20x16x2, DL_CHR20x16x2,
DL_MAP40x8x4, DL_MAP40x8x4,
DL_MAP80x4x2, DL_MAP80x4x2,
DL_MAP80x4x4, DL_MAP80x4x4,
DL_MAP160x2x2, DL_MAP160x2x2,
DL_MAP160x1x2, DL_MAP160x1x2,
DL_MAP160x2x4, DL_MAP160x2x4,
DL_MAP160x1x4, DL_MAP160x1x4,
DL_MAP320x1x1, DL_MAP320x1x1,
DL_JVB, DL_JVB,
DL_JMP DL_JMP
}; };
unsigned char dlend = 0;
/* We know that the sizeof expression is constant; don't tell us. */
#pragma warn (const-comparison, off)
int int
main(void) main(void)
{ {
// unfortunately "sizeof()" doesn't work with void data int returnValue = (sizeof DisplayList != 28); // assure only one byte per instruction!
// (Error: Size of data type is unknown)
// so we trick with the addresses at front and end...
int returnValue = (((unsigned int)&dlend-(unsigned int)&DisplayList) != 28); // assure only one byte per instruction!
clrscr(); clrscr();
if (returnValue) if (returnValue)
@ -66,4 +62,3 @@ main(void)
return returnValue; return returnValue;
} }