473,382 Members | 1,423 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

i want to use functions that don't return int, without declaring them

Hi,

If I want to call functions that don't return int without declaring
them, will there be any harm?

I only want to assign the function(return value) to the type that it
returns, so I don't see how the return value comes to play here.
Ex
int main
{
double val;

val = func();
/* when return value comes here, its a double */

return EXIT_SUCCESS;
}
double func(void)
{
return 5;
/* this will convert 5 to a double value before passing back*/
}

I know why we have prototypes, but declarations I have no clue how they
are useful. The actual function's code will convert the return value
to the proper type, in the call location if we(programmer) know what
type the function is returning, then why do we need declarations? How
do they help?

Nov 14 '05 #1
16 1957
On 2005-02-16 19:22:01 -0500, "G Patel" <ga********@gmail.com> said:
Hi,

If I want to call functions that don't return int without declaring
them, will there be any harm?

I only want to assign the function(return value) to the type that it
returns, so I don't see how the return value comes to play here.
This is undefined behavior, don't do it. It may work by chance on some
platforms, but you have no guarantee of that.

Imagine, for instance, a platform that has seperate floating point
registers and integer registers that are used to return function results
Ex

int main
{
double val;
On this hypothetical platform, the compiler says "hey, this function
func must be 'int func()', so I should look for the return value in the
integer register".
It calls the function, and fetches the value in the integer register
(which is likely garbage).
It then converts that garbage int value to a double, val now has a
garbage value.
val = func();
/* when return value comes here, its a double */

return EXIT_SUCCESS;
}
double func(void)
{
return 5;
/* this will convert 5 to a double value before passing back*/
Yes it will, and on our hypothetical platform, it stuffs that value
into the floating point register, while leaving the integer register
with an undefined value. }

....Or none of that could happen, such is the nature of undefined
behavior. Moral of the story: don't do it.

Also, note that your code won't even compile on a C99 compiler where
implicit int is no longer supported.
I know why we have prototypes, but declarations I have no clue how they
are useful. The actual function's code will convert the return value
to the proper type, in the call location if we(programmer) know what
type the function is returning, then why do we need declarations? How
do they help?


Because without them, your program exhibits undefined behavior. Period.

--
Clark S. Cox, III
cl*******@gmail.com

Nov 14 '05 #2

G Patel wrote:
Hi,

If I want to call functions that don't return int without declaring
them,
Why?
will there be any harm?


It's illegal and your compiler should issue a diagnostic for an
undeclared function. Only functions returning int could be undeclared
under the old standard. As of C99, that's not even legal.

Brian

Nov 14 '05 #3
G Patel wrote:

If I want to call functions that don't return int without
declaring them, will there be any harm?
Yes.
I only want to assign the function(return value) to the type
that it returns, so I don't see how the return value comes to
play here.

int main
Not a good example.
{
double val;

val = func();
/* when return value comes here, its a double */
No. It comes as an int, becasue that's what you've implicitly
told the compiler. Note that your code is a constraint violation
under C99.
return EXIT_SUCCESS;
}

double func(void)
{
return 5;
/* this will convert 5 to a double value before passing back*/
}

I know why we have prototypes,
It seems that you don't.
but declarations I have no clue how they are useful.
The actual function's code will convert the return value
to the proper type, in the call location if we(programmer)
know what type the function is returning, then why do we need
declarations? How do they help?


Implementations typically have a precise mechanism for returning
function values. This may be a stack or specific register. The
calling function only knows the return mechanism by knowing
the (possibly implied) function signature.

More pragmatically: func may return an 8 byte value on a stack,
or it may return a value through a floating point register. Given
an implicit int return type, the calling function may assume that
func returns a 4 byte int on the stack, or a value through an
integer register.

--
Peter

Nov 14 '05 #4
In article <2005021619321316807%clarkcox3@gmailcom>,
Clark S. Cox III <cl*******@gmail.com> wrote:
:Imagine, for instance, a platform that has seperate floating point
:registers and integer registers that are used to return function results

That hypothetical is, as I recall, instantiated for MIPS R4x00/
R8000/ R1000/ R12000 ABI on SGI's IRIX, and probably other
systems as well.

The IRIX mips3/mips4 ABI also has rules for returning small structures
in registers. Which is, incidently, a point that the OP missed: that
structures can be returned as results, and if you don't declare that as
your return type, you are fairly unlikely to just happen to get
everything squished into the right registers.
--
Can a statement be self-referential without knowing it?
Nov 14 '05 #5

Clark S. Cox III wrote:
On 2005-02-16 19:22:01 -0500, "G Patel" <ga********@gmail.com> said:
Hi,

If I want to call functions that don't return int without declaring
them, will there be any harm?

I only want to assign the function(return value) to the type that it returns, so I don't see how the return value comes to play here.
This is undefined behavior, don't do it. It may work by chance on

some platforms, but you have no guarantee of that.

Imagine, for instance, a platform that has seperate floating point
registers and integer registers that are used to return function results

Ohh, makes sense now. But now how do non-prototyped function calls
handle parameter passing. Someone communication is made between the
call and the actual function code. Parameter passing works without a
prototype, why can't a return variable work without a declaration?

Ex

int main
{
double val;
On this hypothetical platform, the compiler says "hey, this function
func must be 'int func()', so I should look for the return value in

the integer register".
It calls the function, and fetches the value in the integer register
(which is likely garbage).
It then converts that garbage int value to a double, val now has a
garbage value.
val = func();
/* when return value comes here, its a double */

return EXIT_SUCCESS;
}
double func(void)
{
return 5;
/* this will convert 5 to a double value before passing back*/


Yes it will, and on our hypothetical platform, it stuffs that value
into the floating point register, while leaving the integer register
with an undefined value.
}


Yes, but parameter passing without declarations would be a "bigger"
case of what you are saying, but C compilers handle it properly.
Ex.

double func(); /* parameters not specified */

int main(void)
{
double i;

i = func(4, 6);

return EXIT_SUCCESS;
}

/* in another file */
double func(short x, short y)
{
return (double)x + y;
}
/* This works fine, even though main doesn't know anything about func's
parameters. It still manages to call func. How come return values are
more tricky? */

Nov 14 '05 #6

G Patel wrote:
Clark S. Cox III wrote:
On 2005-02-16 19:22:01 -0500, "G Patel" <ga********@gmail.com> said:
Hi,

If I want to call functions that don't return int without declaring them, will there be any harm?

I only want to assign the function(return value) to the type that it returns, so I don't see how the return value comes to play here.
This is undefined behavior, don't do it. It may work by chance on

some
platforms, but you have no guarantee of that.

Imagine, for instance, a platform that has seperate floating point
registers and integer registers that are used to return function

results

Ohh, makes sense now. But now how do non-prototyped function calls
handle parameter passing. Someone communication is made between the
call and the actual function code. Parameter passing works without a
prototype, why can't a return variable work without a declaration?

Ex

int main
{
double val;


On this hypothetical platform, the compiler says "hey, this

function func must be 'int func()', so I should look for the return value in

the
integer register".
It calls the function, and fetches the value in the integer register (which is likely garbage).
It then converts that garbage int value to a double, val now has a
garbage value.
val = func();
/* when return value comes here, its a double */

return EXIT_SUCCESS;
}
double func(void)
{
return 5;
/* this will convert 5 to a double value before passing
back*/
Yes it will, and on our hypothetical platform, it stuffs that value
into the floating point register, while leaving the integer register with an undefined value.
}


Yes, but parameter passing without declarations would be a "bigger"
case of what you are saying, but C compilers handle it properly.
Ex.

double func(); /* parameters not specified */

int main(void)
{
double i;

i = func(4, 6);

return EXIT_SUCCESS;
}

/* in another file */
double func(short x, short y)
{
return (double)x + y;
}
/* This works fine, even though main doesn't know anything about

func's parameters. It still manages to call func. How come return values are more tricky? */

Because parameters/arguments are passed on the stack and the method is
well defined. Return values are less well defined (can be passed back
many different ways, depends on the type).

Nov 14 '05 #7
"G Patel" <ga********@gmail.com> writes:
[...]
Ohh, makes sense now. But now how do non-prototyped function calls
handle parameter passing. Someone communication is made between the
call and the actual function code. Parameter passing works without a
prototype, why can't a return variable work without a declaration?
No, parameter passing doesn't necessarily work correctly without a
prototype. With no prototype in scope, the compiler will make certain
assumptions about the types of the parameters, based on the types of
the arguments that you pass. For example, an argument of type short
will be promoted to int, and an argument of type float will be
promoted to double. If this isn't what the called function is
expecting, you get undefined behavior -- which includes working just
as you expect.

[...] Yes, but parameter passing without declarations would be a "bigger"
case of what you are saying, but C compilers handle it properly.
Ex.

double func(); /* parameters not specified */

int main(void)
{
double i;

i = func(4, 6);

return EXIT_SUCCESS;
}

/* in another file */
double func(short x, short y)
{
return (double)x + y;
}
/* This works fine, even though main doesn't know anything about func's
parameters. It still manages to call func. How come return values are
more tricky? */


The integer constants 4 and 6 are of type int, and are passed that
way. The function expects to receive arguments of type short. If int
and short arguments happen to be passed by the same mechanism (e.g.,
if they're both passed in registers), your program may happen to work.
(It will likely continue to work until it breaks at the most
inconvenient possible moment.)

Incidentally, the program above is not what you actually compiled.
The macro EXIT_SUCCESS is defined in <stdlib.h>; if you're using it,
you must have a "#include <stdlib.h>" that you didn't show us. I'm
guessing your actual program also had a printf() call that displayed
the result of your function call (and, I hope, a "#include <stdio.h"),
leading you to believe that the compiler handled it "properly".

In this particular case it was easy enough to figure out what you
meant, but in general it's a good idea to post a complete compilable
program (preferably a small one); otherwise we'll get hung up on the
differences between what you posted and what you actually compiled.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #8
On 2005-02-16 21:02:32 -0500, ro******@ibd.nrc-cnrc.gc.ca (Walter
Roberson) said:
In article <2005021619321316807%clarkcox3@gmailcom>,
Clark S. Cox III <cl*******@gmail.com> wrote:
:Imagine, for instance, a platform that has seperate floating point
:registers and integer registers that are used to return function
results

That hypothetical is, as I recall, instantiated for MIPS R4x00/
R8000/ R1000/ R12000 ABI on SGI's IRIX, and probably other
systems as well.


I know, PowerPC is the one I had in mind, but I wanted to keep from
using specific implementations as an example.
--
Clark S. Cox, III
cl*******@gmail.com

Nov 14 '05 #9
On 2005-02-16 21:03:44 -0500, "G Patel" <ga********@gmail.com> said:

Yes, but parameter passing without declarations would be a "bigger"
case of what you are saying, but C compilers handle it properly.
Ex.

double func(); /* parameters not specified */

int main(void)
{
double i;

i = func(4, 6);

return EXIT_SUCCESS;
}

/* in another file */
double func(short x, short y)
{
return (double)x + y;
}
/* This works fine, even though main doesn't know anything about func's
parameters. It still manages to call func. How come return values are
more tricky? */


They aren't more tricky, it's the exact same issue. If it works for
you, you just got lucky. It's entirely possible that int and short just
happen to be passed in the same way on your platform, and everything
just happens to line up, but, again, you can't rely on that.
--
Clark S. Cox, III
cl*******@gmail.com

Nov 14 '05 #10
G Patel wrote:
If I want to call functions that don't return int
without declaring them, will there be any harm?
Why didn't you try it?
cat main.c #include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
// When return value comes here, its a double.
double val = func();
fprintf(stderr, "val = %f\n", val);
return EXIT_SUCCESS;
}

double func(void) {
// This will convert 5 to a double value before passing back.
return 5;
}
gcc -Wall -std=c99 -pedantic -o main main.c main.c: In function `main':
main.c:6: warning: implicit declaration of function `func'
main.c: At top level:
main.c:11: error: conflicting types for 'func'
main.c:6: error: previous implicit declaration of 'func' \
was here

If you define func(void) as an external function:
cat func.c double func(void) {
// This will convert 5 to a double value before passing back.
return 5;
}
cat main.c #include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
// When return value comes here, its a double.
double val = func();
fprintf(stderr, "val = %f\n", val);
return EXIT_SUCCESS;
}
gcc -Wall -std=c99 -pedantic -o main main.c func.c main.c: In function `main':
main.c:6: warning: implicit declaration of function `func' ./main val = 16.000000

you get garbage because, in this case, func(void) returns a double
on top of the floating-point stack
but function main is looking for an int in register eax
which it converts to a double.
I only want to assign the function(return value) to the type that it
returns, so I don't see how the return value comes to play here.
The calling function needs to know the type of the return value
so that it knows where to look for it
and so that it can convert it to the type of val if necessary.

[snip]
I know why we have prototypes
but I have no clue how declarations are useful.
The actual function's code will convert the return value
to the proper type, in the call location
if we(programmer) know what type the function is returning,
then why do we need declarations?
How do they help?


The calling function needs to know the type of each argument
and the type of the return value
so that it can perform any necessary conversions.
Suppose, for example, that you have declared

double f(double);

and you want to invoke

double val = f(13);

Without the declaration,
the calling function will try to pass an int to f(double)
and because f(double) expects a double, it will get the wrong value.
But, with the declaration,
the calling function will convert the int 13 to a double 13.0
and pass it to f(double)
so that f(double) gets the type that it expects.
Nov 14 '05 #11
"Luke Wu" <Lo***********@gmail.com> writes:
G Patel wrote:

[...]
/* This works fine, even though main doesn't know anything about
func's parameters. It still manages to call func. How come return
values are more tricky? */

Because parameters/arguments are passed on the stack and the method is
well defined. Return values are less well defined (can be passed back
many different ways, depends on the type).


No, arguments have the same problems as return values. Arguments can
be passed on the stack, in registers, or by carrier pigeon. The code
invokes undefined behavior, as I explained elsethread.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #12

Keith Thompson wrote:
"Luke Wu" <Lo***********@gmail.com> writes:
G Patel wrote:

[...]
/* This works fine, even though main doesn't know anything about
func's parameters. It still manages to call func. How come return values are more tricky? */

Because parameters/arguments are passed on the stack and the method is well defined. Return values are less well defined (can be passed back many different ways, depends on the type).


No, arguments have the same problems as return values. Arguments can
be passed on the stack, in registers, or by carrier pigeon. The code
invokes undefined behavior, as I explained elsethread.


The code does not invoke undefined behavior preC99, because the
arguments being passed will be promoted to in, so will the parameters.

Arguments don't have the same problems if they are equal to and below
the rank of int, and the corresponding parameters in the function
definitions are also. Both arguments and paremetesr will be promoted
to int explicity, and everything is fine.

Nov 14 '05 #13
"Luke Wu" <Lo***********@gmail.com> writes:
Keith Thompson wrote:
"Luke Wu" <Lo***********@gmail.com> writes:
> G Patel wrote:

[...]
>> /* This works fine, even though main doesn't know anything about
>> func's parameters. It still manages to call func. How come
>> return values are more tricky? */
>
>
> Because parameters/arguments are passed on the stack and the
> method is well defined. Return values are less well defined (can
> be passed back many different ways, depends on the type).


No, arguments have the same problems as return values. Arguments can
be passed on the stack, in registers, or by carrier pigeon. The code
invokes undefined behavior, as I explained elsethread.


The code does not invoke undefined behavior preC99, because the
arguments being passed will be promoted to in, so will the parameters.

Arguments don't have the same problems if they are equal to and below
the rank of int, and the corresponding parameters in the function
definitions are also. Both arguments and paremetesr will be promoted
to int explicity, and everything is fine.


I don't think that's correct.

Here's the code in question:

double func(); /* parameters not specified */

int main(void)
{
double i;

i = func(4, 6);

return EXIT_SUCCESS;
}

/* in another file */
double func(short x, short y)
{
return (double)x + y;
}

In the absence of a prototype, the call func(6, 4) passes two int
arguments to func, which is expecting two short arguments. If the
first line had been replaced with:

double func(short x, short y);

the arguments would have been implicitly converted from int to short
before being passed to the function. It's common, but not required,
for int and short arguments to be passed the same way.

C99 6.5.2.2 says:

If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed
on each argument, and arguments that have type float are promoted
to double.
[snip]
If the function is defined with a type that does not include a
prototype, and the types of the arguments after promotion are not
compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:
[snip]

I believe C90 has the same rules.

Even if the arguments were objects of type short, their values would
be promoted to int, invoking undefined behavior. The solution is
simple: always use prototypes.

Pre-ANSI C didn't have prototypes, and it didn't allow parameters of
type short (you could declare parameters to be of type short, but they
were really int), so this issue didn't arise.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #14
Luke Wu wrote:
Keith Thompson wrote:
"Luke Wu" <Lo***********@gmail.com> writes:
G Patel wrote:
[...]
/* This works fine, even though main doesn't know anything about
func's parameters. It still manages to call func. How come
return
values are more tricky? */
Because parameters/arguments are passed on the stack and the method
is
well defined. Return values are less well defined (can be passed
back
many different ways, depends on the type).


No, arguments have the same problems as return values. Arguments can
be passed on the stack, in registers, or by carrier pigeon. The code
invokes undefined behavior, as I explained elsethread.

The code does not invoke undefined behavior preC99, because the
arguments being passed will be promoted to in, so will the parameters.


Yes it does invoke undefined behaviour. New-style function definitions
don't have this "parameter promotion" feature you're talking about. If
the poster had an old-style function with short parameters, then yes
they will be promoted upto int(or unsigned int) just like the passed in
arguments. But all this is irrelevant, because any new code should have
prototyped declarations and new-style prototyped function definitions
(of course you can use the later as the former in many cases).

Arguments don't have the same problems if they are equal to and below
the rank of int, and the corresponding parameters in the function
definitions are also. Both arguments and paremetesr will be promoted
to int explicity, and everything is fine.


Since the calling site was not in the scope of any explicit
declarations, yes the arguments will be promoted, but the corresponding
parameters in the function definition (shorts) will not be promoted
(that's only with old style definitions). The call is sending INTs or
UNSIGNED INTs (based on value preserving rules and promotion) but the
function is expecting SHORTS (not expecting short promoted types). This
invokes undefined behaviour like Keith said.
Under C99, many things I've explained above as being "okay" are also
disallowed.

Nov 14 '05 #15
Luke Wu wrote:

The code [snipped] does not invoke undefined behavior preC99,
because the arguments being passed will be promoted to in, so
will the parameters.


This is loose wording which C99 has corrected.

Given...

void baa(void)
{
short y = 42;
foo(y);
}

void foo(short x)
{
printf("%d\n", (int) sizeof(x));
}

....then x is a parameter, y is an argument. Since foo() is
unprototyped in the call from baa(), y will be promoted to
int. However, x will always have the type short, because that's
how it's declared. [Of course, x is potentially subject to
integral promotion within expressions which might use it.]

--
Peter

Nov 14 '05 #16
On 17 Feb 2005 09:31:21 -0800, in comp.lang.c , "Luke Wu"
<Lo***********@gmail.com> wrote:
The code does not invoke undefined behavior preC99, because the
arguments being passed will be promoted to in, so will the parameters.

Arguments don't have the same problems if they are equal to and below
the rank of int, and the corresponding parameters in the function
definitions are also. Both arguments and paremetesr will be promoted
to int explicity, and everything is fine.


I once ported a programme that made this kind of assumption. It broke
horribly on a different arch, because on the original platform, short and
int were the same width, whereas on the new platform, it was long and int.
Thus the caller pushed two longs onto the stack (or possibly into a
register, or into one carrier pigeon's pouch), and the callee read two
shorts back off. *bang*
On another platform I worked with, ISTR that shorts got pushed in
registers, and longs on the stack, so the callee would have been looking in
completely the wrong place.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>

----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 14 '05 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: will taubin | last post by:
i would like my program to have a config.php with passwords and other stuff. i would like to have a functions.php to hold all my functions. i would like the functions.php to include/require...
19
by: Ross A. Finlayson | last post by:
Hi, I hope you can help me understand the varargs facility. Say I am programming in ISO C including stdarg.h and I declare a function as so: void log_printf(const char* logfilename, const...
110
by: Gregory Pietsch | last post by:
I'm writing a portable implementation of the C standard library for http://www.clc-wiki.net and I was wondering if someone could check the functions in math.h for sanity/portability/whatever. I'm...
7
by: zeecanvas | last post by:
Hi, First of all: Yes, I know global variables are bad, but I've a huge amount of legacy code, and I've to maintain it _as_is_. I'm maintaining a big program. I moved all (program-wide scope)...
1
by: Ilya N. Golubev | last post by:
There is already one function processing pointer values this way. And there may easily appear more, including wrappers for this function. For purposes of further discussion, consider simplified...
4
by: Steven T. Hatton | last post by:
<quote url="http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=53&rl=1"> exported Templates Last updated Sep 6, 2006. exported Templates The separate compilation model enables...
10
by: John Goche | last post by:
Hello, page 202 of Symbian OS Explained by Jo Stichbury states "All virtual functions, public, protected or private, should be exported" then page 203 states "In the rare cases where a...
23
by: Anil Gupte | last post by:
I am trying to set up a function that connects to the database that I can then use gloablly. I set up a class called L3Global in which I have a function as follows: Public Function...
17
by: Jess | last post by:
Hello, If I have a class that has virtual but non-pure declarations, like class A{ virtual void f(); }; Then is A still an abstract class? Do I have to have "virtual void f() = 0;"...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.