Should I place the parameter storage class specifier in the function definition or in both the declaration...
I'm working on porting some old K&R code to ANSI C, so I'm writing missing function prototype declarations. A lot of the function definitions have parameters with the register storage class, but I'm not sure if the register storage class specifier can be omitted in the function prototype?
With and without the register storage class specific declaration, the code compiles correctly (I tried GCC, VC++ and Watcom C). I could not find any information in the ISO/ANSI C89 standard on what is the correct way to do - is it OK if I just put the register keyword in the function definition?
int add(register int x, register int y);
int add(register int x, register int y)
{
return x+y;
}
This also builds correctly:
int add(int x, int y);
int add(register int x, register int y)
{
return x+y;
}
I want to make sure that the register storage specifier is really taken into account, according to the standard (my target is to compile using a very old compiler where this storage class specifier is important). Are both OK and it's just a question of coding style, or not?
c declaration definition c89
|
show 3 more comments
I'm working on porting some old K&R code to ANSI C, so I'm writing missing function prototype declarations. A lot of the function definitions have parameters with the register storage class, but I'm not sure if the register storage class specifier can be omitted in the function prototype?
With and without the register storage class specific declaration, the code compiles correctly (I tried GCC, VC++ and Watcom C). I could not find any information in the ISO/ANSI C89 standard on what is the correct way to do - is it OK if I just put the register keyword in the function definition?
int add(register int x, register int y);
int add(register int x, register int y)
{
return x+y;
}
This also builds correctly:
int add(int x, int y);
int add(register int x, register int y)
{
return x+y;
}
I want to make sure that the register storage specifier is really taken into account, according to the standard (my target is to compile using a very old compiler where this storage class specifier is important). Are both OK and it's just a question of coding style, or not?
c declaration definition c89
What's the target compiler / system?
– dbush
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
1
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
2
@EugeneSh. It's not an exception. Storage classes are never included in type information.auto int x;
,static int x;
, andregister int x;
all have typeint
.
– PSkocik
11 hours ago
1
@PSkocik Whyauto
can't be included butregister
can (well,static
would not make sense)?
– Eugene Sh.
10 hours ago
|
show 3 more comments
I'm working on porting some old K&R code to ANSI C, so I'm writing missing function prototype declarations. A lot of the function definitions have parameters with the register storage class, but I'm not sure if the register storage class specifier can be omitted in the function prototype?
With and without the register storage class specific declaration, the code compiles correctly (I tried GCC, VC++ and Watcom C). I could not find any information in the ISO/ANSI C89 standard on what is the correct way to do - is it OK if I just put the register keyword in the function definition?
int add(register int x, register int y);
int add(register int x, register int y)
{
return x+y;
}
This also builds correctly:
int add(int x, int y);
int add(register int x, register int y)
{
return x+y;
}
I want to make sure that the register storage specifier is really taken into account, according to the standard (my target is to compile using a very old compiler where this storage class specifier is important). Are both OK and it's just a question of coding style, or not?
c declaration definition c89
I'm working on porting some old K&R code to ANSI C, so I'm writing missing function prototype declarations. A lot of the function definitions have parameters with the register storage class, but I'm not sure if the register storage class specifier can be omitted in the function prototype?
With and without the register storage class specific declaration, the code compiles correctly (I tried GCC, VC++ and Watcom C). I could not find any information in the ISO/ANSI C89 standard on what is the correct way to do - is it OK if I just put the register keyword in the function definition?
int add(register int x, register int y);
int add(register int x, register int y)
{
return x+y;
}
This also builds correctly:
int add(int x, int y);
int add(register int x, register int y)
{
return x+y;
}
I want to make sure that the register storage specifier is really taken into account, according to the standard (my target is to compile using a very old compiler where this storage class specifier is important). Are both OK and it's just a question of coding style, or not?
c declaration definition c89
c declaration definition c89
edited 5 hours ago
John Conde
185k80372423
185k80372423
asked 11 hours ago
Carl Eric CodereCarl Eric Codere
965
965
What's the target compiler / system?
– dbush
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
1
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
2
@EugeneSh. It's not an exception. Storage classes are never included in type information.auto int x;
,static int x;
, andregister int x;
all have typeint
.
– PSkocik
11 hours ago
1
@PSkocik Whyauto
can't be included butregister
can (well,static
would not make sense)?
– Eugene Sh.
10 hours ago
|
show 3 more comments
What's the target compiler / system?
– dbush
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
1
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
2
@EugeneSh. It's not an exception. Storage classes are never included in type information.auto int x;
,static int x;
, andregister int x;
all have typeint
.
– PSkocik
11 hours ago
1
@PSkocik Whyauto
can't be included butregister
can (well,static
would not make sense)?
– Eugene Sh.
10 hours ago
What's the target compiler / system?
– dbush
11 hours ago
What's the target compiler / system?
– dbush
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
1
1
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
2
2
@EugeneSh. It's not an exception. Storage classes are never included in type information.
auto int x;
, static int x;
, and register int x;
all have type int
.– PSkocik
11 hours ago
@EugeneSh. It's not an exception. Storage classes are never included in type information.
auto int x;
, static int x;
, and register int x;
all have type int
.– PSkocik
11 hours ago
1
1
@PSkocik Why
auto
can't be included but register
can (well, static
would not make sense)?– Eugene Sh.
10 hours ago
@PSkocik Why
auto
can't be included but register
can (well, static
would not make sense)?– Eugene Sh.
10 hours ago
|
show 3 more comments
5 Answers
5
active
oldest
votes
The key provision is that every declaration of the function must specify a compatible type for it. That requires compatible return types, and, for declarations such as yours that contain parameter lists, compatible type for each pair of corresponding parameters.
The question then becomes whether storage-class specifiers differentiate types. They do not, though the standard says that indirectly, by omission of storage-class specifiers from its discussion of type derivation. The property specified by a storage-class specifier in an object's declaration is therefore separate from that object's type.
Moreover, C89 specifically says
The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition.
(emphasis added). A function definition is a declaration accompanied by a function body, as opposed to a forward declaration, so your two codes have identical semantics.
With and without the register storage class specific declaration, the
code compiles correctly (I tried gcc, VC++ and Watcom), I could not
find any information in the ISO/ANSI C89 standard on what is the
correct way to do, or is it ok if i just put the register keyword in
the function definition?
Personally, I would be inclined to make each forward declaration identical to the declaration in the corresponding function definition. This is never wrong if the function definition itself is correct.
HOWEVER,
The
register
keyword is a relic. Compilers are not obligated to make any attempt at all to actually assignregister
variables to registers, and modern compilers are a lot better than humans at deciding how to assign variables to registers and otherwise to generate fast code anyway. As long as you're converting old code, I would take the opportunity to remove all appearances of theregister
keyword.C89 is obsolete. The latest version of the standard is C 2018; C 2011 is widely deployed; and C99 (also, technically, obsolete) is available almost everywhere. Perhaps there is a good reason for you to target C89, but you should strongly consider instead targeting C11 or C18, or at least C99.
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
add a comment |
Empirically on gcc and clang, the register
storage class on function params
is behaving the same as top-level qualifiers on params: only the ones in the definition (not a previous prototype) count.
(as for top level qualifiers, they're also discarded when type compatibility is considered, i.e., void f(int);
and void f(int const);
are compatible prototypes, but storage classes aren't part of types so type compatibility isn't an issue with them in the first place)
From the point of view of a C programmer, the only observable upshot of register
in C is that the compiler will not let you take the address of the declared object.
When I do:
void f(int A, int register B);
void f(int register A, int B)
{
/*&A;*/ //doesn't compile => A does have register storage here
&B; //compiles => B doesn't have register storage here;
//the register from the previous prototype wasn't considered
}
then &B
compiles, but &A
doesn't, so only the qualifiers in the definition appear to count.
I think that if you do need those register
, your best bet is to use it consistently in both places (the register
in prototypes could theoretically modify how calls are made).
add a comment |
Since you're using an old compiler for an odd platform, sometimes just looking at what the compiler does is more important than assuming it will comply perfectly with the C spec.
This means you want to run each variant of your example through the compiler, with the compiler option set to generate assembly instead of an executable. Look at the assembly, and see if you can tell it is using registers or not each way. In gcc, this is the S
option; for example:
gcc myfile.c -S -o myfile.s
add a comment |
The C89 standard does say this (§ 3.5.4.3 External definitions):
The only storage-class specifier that shall occur in a parameter declaration is
register
.
So, it would appear that while register
is permissible as a function parameter storage class specifier, I still believe that whether or not this is honored really depends on the architecture and calling convention for the function.
Since you mentioned Watcom and C89, I'm going to assume you're targeting x86-16. The typical calling conventions for x86-16 (pascal, stdcall, and cdecl) all require parameters to be pushed on the stack, not in registers, so I doubt that the keyword would actually modify how the parameters are passed to the function at the call site.
Consider, you have the following function definition:
int __stdcall add2(register int x, register int y);
The function goes into the object file as _add2@4
per requirements for stdcall. The @4 indicates how many bytes to remove from the stack at function return. The ret imm16
(return to calling procedure and pop imm16 bytes from stack) instruction is used in this case.
add2
will then have the following ret
at the end:
ret 4
If 4 bytes were not pushed on the stack at the call site (i.e. because the parameters were actually in registers), your program now has a misaligned stack and crashes.
add a comment |
From C17 standard, 6.7.1 Storage-class specifiers:
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined.
Imply that the compiler will try, or not depending on compiler, to speed-up parameter access, but doesn't imply any modification to the calling convention (basically no modifications on calling side).
So it should be present in the function definition, but is insignificant in prototype.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54674465%2fshould-i-place-the-parameter-storage-class-specifier-in-the-function-definition%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
The key provision is that every declaration of the function must specify a compatible type for it. That requires compatible return types, and, for declarations such as yours that contain parameter lists, compatible type for each pair of corresponding parameters.
The question then becomes whether storage-class specifiers differentiate types. They do not, though the standard says that indirectly, by omission of storage-class specifiers from its discussion of type derivation. The property specified by a storage-class specifier in an object's declaration is therefore separate from that object's type.
Moreover, C89 specifically says
The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition.
(emphasis added). A function definition is a declaration accompanied by a function body, as opposed to a forward declaration, so your two codes have identical semantics.
With and without the register storage class specific declaration, the
code compiles correctly (I tried gcc, VC++ and Watcom), I could not
find any information in the ISO/ANSI C89 standard on what is the
correct way to do, or is it ok if i just put the register keyword in
the function definition?
Personally, I would be inclined to make each forward declaration identical to the declaration in the corresponding function definition. This is never wrong if the function definition itself is correct.
HOWEVER,
The
register
keyword is a relic. Compilers are not obligated to make any attempt at all to actually assignregister
variables to registers, and modern compilers are a lot better than humans at deciding how to assign variables to registers and otherwise to generate fast code anyway. As long as you're converting old code, I would take the opportunity to remove all appearances of theregister
keyword.C89 is obsolete. The latest version of the standard is C 2018; C 2011 is widely deployed; and C99 (also, technically, obsolete) is available almost everywhere. Perhaps there is a good reason for you to target C89, but you should strongly consider instead targeting C11 or C18, or at least C99.
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
add a comment |
The key provision is that every declaration of the function must specify a compatible type for it. That requires compatible return types, and, for declarations such as yours that contain parameter lists, compatible type for each pair of corresponding parameters.
The question then becomes whether storage-class specifiers differentiate types. They do not, though the standard says that indirectly, by omission of storage-class specifiers from its discussion of type derivation. The property specified by a storage-class specifier in an object's declaration is therefore separate from that object's type.
Moreover, C89 specifically says
The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition.
(emphasis added). A function definition is a declaration accompanied by a function body, as opposed to a forward declaration, so your two codes have identical semantics.
With and without the register storage class specific declaration, the
code compiles correctly (I tried gcc, VC++ and Watcom), I could not
find any information in the ISO/ANSI C89 standard on what is the
correct way to do, or is it ok if i just put the register keyword in
the function definition?
Personally, I would be inclined to make each forward declaration identical to the declaration in the corresponding function definition. This is never wrong if the function definition itself is correct.
HOWEVER,
The
register
keyword is a relic. Compilers are not obligated to make any attempt at all to actually assignregister
variables to registers, and modern compilers are a lot better than humans at deciding how to assign variables to registers and otherwise to generate fast code anyway. As long as you're converting old code, I would take the opportunity to remove all appearances of theregister
keyword.C89 is obsolete. The latest version of the standard is C 2018; C 2011 is widely deployed; and C99 (also, technically, obsolete) is available almost everywhere. Perhaps there is a good reason for you to target C89, but you should strongly consider instead targeting C11 or C18, or at least C99.
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
add a comment |
The key provision is that every declaration of the function must specify a compatible type for it. That requires compatible return types, and, for declarations such as yours that contain parameter lists, compatible type for each pair of corresponding parameters.
The question then becomes whether storage-class specifiers differentiate types. They do not, though the standard says that indirectly, by omission of storage-class specifiers from its discussion of type derivation. The property specified by a storage-class specifier in an object's declaration is therefore separate from that object's type.
Moreover, C89 specifically says
The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition.
(emphasis added). A function definition is a declaration accompanied by a function body, as opposed to a forward declaration, so your two codes have identical semantics.
With and without the register storage class specific declaration, the
code compiles correctly (I tried gcc, VC++ and Watcom), I could not
find any information in the ISO/ANSI C89 standard on what is the
correct way to do, or is it ok if i just put the register keyword in
the function definition?
Personally, I would be inclined to make each forward declaration identical to the declaration in the corresponding function definition. This is never wrong if the function definition itself is correct.
HOWEVER,
The
register
keyword is a relic. Compilers are not obligated to make any attempt at all to actually assignregister
variables to registers, and modern compilers are a lot better than humans at deciding how to assign variables to registers and otherwise to generate fast code anyway. As long as you're converting old code, I would take the opportunity to remove all appearances of theregister
keyword.C89 is obsolete. The latest version of the standard is C 2018; C 2011 is widely deployed; and C99 (also, technically, obsolete) is available almost everywhere. Perhaps there is a good reason for you to target C89, but you should strongly consider instead targeting C11 or C18, or at least C99.
The key provision is that every declaration of the function must specify a compatible type for it. That requires compatible return types, and, for declarations such as yours that contain parameter lists, compatible type for each pair of corresponding parameters.
The question then becomes whether storage-class specifiers differentiate types. They do not, though the standard says that indirectly, by omission of storage-class specifiers from its discussion of type derivation. The property specified by a storage-class specifier in an object's declaration is therefore separate from that object's type.
Moreover, C89 specifically says
The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is ignored unless the declared parameter is one of the members of the parameter type list for a function definition.
(emphasis added). A function definition is a declaration accompanied by a function body, as opposed to a forward declaration, so your two codes have identical semantics.
With and without the register storage class specific declaration, the
code compiles correctly (I tried gcc, VC++ and Watcom), I could not
find any information in the ISO/ANSI C89 standard on what is the
correct way to do, or is it ok if i just put the register keyword in
the function definition?
Personally, I would be inclined to make each forward declaration identical to the declaration in the corresponding function definition. This is never wrong if the function definition itself is correct.
HOWEVER,
The
register
keyword is a relic. Compilers are not obligated to make any attempt at all to actually assignregister
variables to registers, and modern compilers are a lot better than humans at deciding how to assign variables to registers and otherwise to generate fast code anyway. As long as you're converting old code, I would take the opportunity to remove all appearances of theregister
keyword.C89 is obsolete. The latest version of the standard is C 2018; C 2011 is widely deployed; and C99 (also, technically, obsolete) is available almost everywhere. Perhaps there is a good reason for you to target C89, but you should strongly consider instead targeting C11 or C18, or at least C99.
edited 4 hours ago
answered 10 hours ago
John BollingerJohn Bollinger
81.8k74277
81.8k74277
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
add a comment |
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
You are right, @GovindParmar. I have reworded that section of the answer.
– John Bollinger
4 hours ago
add a comment |
Empirically on gcc and clang, the register
storage class on function params
is behaving the same as top-level qualifiers on params: only the ones in the definition (not a previous prototype) count.
(as for top level qualifiers, they're also discarded when type compatibility is considered, i.e., void f(int);
and void f(int const);
are compatible prototypes, but storage classes aren't part of types so type compatibility isn't an issue with them in the first place)
From the point of view of a C programmer, the only observable upshot of register
in C is that the compiler will not let you take the address of the declared object.
When I do:
void f(int A, int register B);
void f(int register A, int B)
{
/*&A;*/ //doesn't compile => A does have register storage here
&B; //compiles => B doesn't have register storage here;
//the register from the previous prototype wasn't considered
}
then &B
compiles, but &A
doesn't, so only the qualifiers in the definition appear to count.
I think that if you do need those register
, your best bet is to use it consistently in both places (the register
in prototypes could theoretically modify how calls are made).
add a comment |
Empirically on gcc and clang, the register
storage class on function params
is behaving the same as top-level qualifiers on params: only the ones in the definition (not a previous prototype) count.
(as for top level qualifiers, they're also discarded when type compatibility is considered, i.e., void f(int);
and void f(int const);
are compatible prototypes, but storage classes aren't part of types so type compatibility isn't an issue with them in the first place)
From the point of view of a C programmer, the only observable upshot of register
in C is that the compiler will not let you take the address of the declared object.
When I do:
void f(int A, int register B);
void f(int register A, int B)
{
/*&A;*/ //doesn't compile => A does have register storage here
&B; //compiles => B doesn't have register storage here;
//the register from the previous prototype wasn't considered
}
then &B
compiles, but &A
doesn't, so only the qualifiers in the definition appear to count.
I think that if you do need those register
, your best bet is to use it consistently in both places (the register
in prototypes could theoretically modify how calls are made).
add a comment |
Empirically on gcc and clang, the register
storage class on function params
is behaving the same as top-level qualifiers on params: only the ones in the definition (not a previous prototype) count.
(as for top level qualifiers, they're also discarded when type compatibility is considered, i.e., void f(int);
and void f(int const);
are compatible prototypes, but storage classes aren't part of types so type compatibility isn't an issue with them in the first place)
From the point of view of a C programmer, the only observable upshot of register
in C is that the compiler will not let you take the address of the declared object.
When I do:
void f(int A, int register B);
void f(int register A, int B)
{
/*&A;*/ //doesn't compile => A does have register storage here
&B; //compiles => B doesn't have register storage here;
//the register from the previous prototype wasn't considered
}
then &B
compiles, but &A
doesn't, so only the qualifiers in the definition appear to count.
I think that if you do need those register
, your best bet is to use it consistently in both places (the register
in prototypes could theoretically modify how calls are made).
Empirically on gcc and clang, the register
storage class on function params
is behaving the same as top-level qualifiers on params: only the ones in the definition (not a previous prototype) count.
(as for top level qualifiers, they're also discarded when type compatibility is considered, i.e., void f(int);
and void f(int const);
are compatible prototypes, but storage classes aren't part of types so type compatibility isn't an issue with them in the first place)
From the point of view of a C programmer, the only observable upshot of register
in C is that the compiler will not let you take the address of the declared object.
When I do:
void f(int A, int register B);
void f(int register A, int B)
{
/*&A;*/ //doesn't compile => A does have register storage here
&B; //compiles => B doesn't have register storage here;
//the register from the previous prototype wasn't considered
}
then &B
compiles, but &A
doesn't, so only the qualifiers in the definition appear to count.
I think that if you do need those register
, your best bet is to use it consistently in both places (the register
in prototypes could theoretically modify how calls are made).
edited 10 hours ago
answered 11 hours ago
PSkocikPSkocik
33.5k65474
33.5k65474
add a comment |
add a comment |
Since you're using an old compiler for an odd platform, sometimes just looking at what the compiler does is more important than assuming it will comply perfectly with the C spec.
This means you want to run each variant of your example through the compiler, with the compiler option set to generate assembly instead of an executable. Look at the assembly, and see if you can tell it is using registers or not each way. In gcc, this is the S
option; for example:
gcc myfile.c -S -o myfile.s
add a comment |
Since you're using an old compiler for an odd platform, sometimes just looking at what the compiler does is more important than assuming it will comply perfectly with the C spec.
This means you want to run each variant of your example through the compiler, with the compiler option set to generate assembly instead of an executable. Look at the assembly, and see if you can tell it is using registers or not each way. In gcc, this is the S
option; for example:
gcc myfile.c -S -o myfile.s
add a comment |
Since you're using an old compiler for an odd platform, sometimes just looking at what the compiler does is more important than assuming it will comply perfectly with the C spec.
This means you want to run each variant of your example through the compiler, with the compiler option set to generate assembly instead of an executable. Look at the assembly, and see if you can tell it is using registers or not each way. In gcc, this is the S
option; for example:
gcc myfile.c -S -o myfile.s
Since you're using an old compiler for an odd platform, sometimes just looking at what the compiler does is more important than assuming it will comply perfectly with the C spec.
This means you want to run each variant of your example through the compiler, with the compiler option set to generate assembly instead of an executable. Look at the assembly, and see if you can tell it is using registers or not each way. In gcc, this is the S
option; for example:
gcc myfile.c -S -o myfile.s
edited 8 hours ago
Cody Gray♦
193k35378465
193k35378465
answered 11 hours ago
JohnHJohnH
2,308718
2,308718
add a comment |
add a comment |
The C89 standard does say this (§ 3.5.4.3 External definitions):
The only storage-class specifier that shall occur in a parameter declaration is
register
.
So, it would appear that while register
is permissible as a function parameter storage class specifier, I still believe that whether or not this is honored really depends on the architecture and calling convention for the function.
Since you mentioned Watcom and C89, I'm going to assume you're targeting x86-16. The typical calling conventions for x86-16 (pascal, stdcall, and cdecl) all require parameters to be pushed on the stack, not in registers, so I doubt that the keyword would actually modify how the parameters are passed to the function at the call site.
Consider, you have the following function definition:
int __stdcall add2(register int x, register int y);
The function goes into the object file as _add2@4
per requirements for stdcall. The @4 indicates how many bytes to remove from the stack at function return. The ret imm16
(return to calling procedure and pop imm16 bytes from stack) instruction is used in this case.
add2
will then have the following ret
at the end:
ret 4
If 4 bytes were not pushed on the stack at the call site (i.e. because the parameters were actually in registers), your program now has a misaligned stack and crashes.
add a comment |
The C89 standard does say this (§ 3.5.4.3 External definitions):
The only storage-class specifier that shall occur in a parameter declaration is
register
.
So, it would appear that while register
is permissible as a function parameter storage class specifier, I still believe that whether or not this is honored really depends on the architecture and calling convention for the function.
Since you mentioned Watcom and C89, I'm going to assume you're targeting x86-16. The typical calling conventions for x86-16 (pascal, stdcall, and cdecl) all require parameters to be pushed on the stack, not in registers, so I doubt that the keyword would actually modify how the parameters are passed to the function at the call site.
Consider, you have the following function definition:
int __stdcall add2(register int x, register int y);
The function goes into the object file as _add2@4
per requirements for stdcall. The @4 indicates how many bytes to remove from the stack at function return. The ret imm16
(return to calling procedure and pop imm16 bytes from stack) instruction is used in this case.
add2
will then have the following ret
at the end:
ret 4
If 4 bytes were not pushed on the stack at the call site (i.e. because the parameters were actually in registers), your program now has a misaligned stack and crashes.
add a comment |
The C89 standard does say this (§ 3.5.4.3 External definitions):
The only storage-class specifier that shall occur in a parameter declaration is
register
.
So, it would appear that while register
is permissible as a function parameter storage class specifier, I still believe that whether or not this is honored really depends on the architecture and calling convention for the function.
Since you mentioned Watcom and C89, I'm going to assume you're targeting x86-16. The typical calling conventions for x86-16 (pascal, stdcall, and cdecl) all require parameters to be pushed on the stack, not in registers, so I doubt that the keyword would actually modify how the parameters are passed to the function at the call site.
Consider, you have the following function definition:
int __stdcall add2(register int x, register int y);
The function goes into the object file as _add2@4
per requirements for stdcall. The @4 indicates how many bytes to remove from the stack at function return. The ret imm16
(return to calling procedure and pop imm16 bytes from stack) instruction is used in this case.
add2
will then have the following ret
at the end:
ret 4
If 4 bytes were not pushed on the stack at the call site (i.e. because the parameters were actually in registers), your program now has a misaligned stack and crashes.
The C89 standard does say this (§ 3.5.4.3 External definitions):
The only storage-class specifier that shall occur in a parameter declaration is
register
.
So, it would appear that while register
is permissible as a function parameter storage class specifier, I still believe that whether or not this is honored really depends on the architecture and calling convention for the function.
Since you mentioned Watcom and C89, I'm going to assume you're targeting x86-16. The typical calling conventions for x86-16 (pascal, stdcall, and cdecl) all require parameters to be pushed on the stack, not in registers, so I doubt that the keyword would actually modify how the parameters are passed to the function at the call site.
Consider, you have the following function definition:
int __stdcall add2(register int x, register int y);
The function goes into the object file as _add2@4
per requirements for stdcall. The @4 indicates how many bytes to remove from the stack at function return. The ret imm16
(return to calling procedure and pop imm16 bytes from stack) instruction is used in this case.
add2
will then have the following ret
at the end:
ret 4
If 4 bytes were not pushed on the stack at the call site (i.e. because the parameters were actually in registers), your program now has a misaligned stack and crashes.
edited 4 hours ago
Antti Haapala
82.9k16159198
82.9k16159198
answered 11 hours ago
Govind ParmarGovind Parmar
10.4k53359
10.4k53359
add a comment |
add a comment |
From C17 standard, 6.7.1 Storage-class specifiers:
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined.
Imply that the compiler will try, or not depending on compiler, to speed-up parameter access, but doesn't imply any modification to the calling convention (basically no modifications on calling side).
So it should be present in the function definition, but is insignificant in prototype.
add a comment |
From C17 standard, 6.7.1 Storage-class specifiers:
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined.
Imply that the compiler will try, or not depending on compiler, to speed-up parameter access, but doesn't imply any modification to the calling convention (basically no modifications on calling side).
So it should be present in the function definition, but is insignificant in prototype.
add a comment |
From C17 standard, 6.7.1 Storage-class specifiers:
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined.
Imply that the compiler will try, or not depending on compiler, to speed-up parameter access, but doesn't imply any modification to the calling convention (basically no modifications on calling side).
So it should be present in the function definition, but is insignificant in prototype.
From C17 standard, 6.7.1 Storage-class specifiers:
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined.
Imply that the compiler will try, or not depending on compiler, to speed-up parameter access, but doesn't imply any modification to the calling convention (basically no modifications on calling side).
So it should be present in the function definition, but is insignificant in prototype.
edited 10 hours ago
answered 11 hours ago
Frankie_CFrankie_C
3,5701723
3,5701723
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54674465%2fshould-i-place-the-parameter-storage-class-specifier-in-the-function-definition%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
What's the target compiler / system?
– dbush
11 hours ago
Take a look here: port70.net/~nsz/c/c11/n1570.html#6.7.6.3 The only storage-class specifier that shall occur in a parameter declaration is register.
– Eugene Sh.
11 hours ago
1
Storage class is not a factor in determining whether types are compatible. Therefore, the type of a function declared with register should be compatible with the type of a function declared without register, if they are otherwise compatible.
– Eric Postpischil
11 hours ago
2
@EugeneSh. It's not an exception. Storage classes are never included in type information.
auto int x;
,static int x;
, andregister int x;
all have typeint
.– PSkocik
11 hours ago
1
@PSkocik Why
auto
can't be included butregister
can (well,static
would not make sense)?– Eugene Sh.
10 hours ago